Start point
This commit is contained in:
34
lib/libusb/.clang-tidy
Normal file
34
lib/libusb/.clang-tidy
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
Checks: "-*,\
|
||||
boost-*,\
|
||||
bugprone-*,\
|
||||
-bugprone-easily-swappable-parameters,\
|
||||
-bugprone-narrowing-conversions,\
|
||||
-bugprone-signed-char-misuse,\
|
||||
-bugprone-switch-missing-default-case,\
|
||||
clang-analyzer-*,\
|
||||
-clang-analyzer-core.NullDereference,\
|
||||
-clang-analyzer-deadcode.DeadStores,\
|
||||
-clang-analyzer-optin.portability.UnixAPI,\
|
||||
-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,\
|
||||
-clang-analyzer-security.insecureAPI.strcpy,\
|
||||
-clang-analyzer-unix.Malloc,\
|
||||
misc-*,\
|
||||
-misc-no-recursion,\
|
||||
-misc-include-cleaner,\
|
||||
modernize-*,\
|
||||
-modernize-macro-to-enum,\
|
||||
performance-*,\
|
||||
-performance-no-int-to-ptr,\
|
||||
-performance-type-promotion-in-math-fn,\
|
||||
portability-*,\
|
||||
readability-*,\
|
||||
-readability-braces-around-statements,\
|
||||
-readability-else-after-return,\
|
||||
-readability-identifier-length,\
|
||||
-readability-function-cognitive-complexity,\
|
||||
-readability-isolate-declaration,\
|
||||
-readability-magic-numbers,\
|
||||
"
|
||||
#WarningsAsErrors: "*"
|
||||
...
|
||||
3
lib/libusb/.codespellrc
Normal file
3
lib/libusb/.codespellrc
Normal file
@@ -0,0 +1,3 @@
|
||||
[codespell]
|
||||
skip = strerror.c,AUTHORS
|
||||
ignore-words-list = numer,ser,xwindows
|
||||
7
lib/libusb/.gitattributes
vendored
Normal file
7
lib/libusb/.gitattributes
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
*.ac eol=lf
|
||||
*.am eol=lf
|
||||
*.bat eol=crlf
|
||||
*.sh eol=lf
|
||||
.gitattributes export-ignore
|
||||
.gitignore export-ignore
|
||||
INSTALL_WIN.txt eol=crlf
|
||||
26
lib/libusb/.github/cifuzz.yml
vendored
Normal file
26
lib/libusb/.github/cifuzz.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: CIFuzz
|
||||
on: [pull_request]
|
||||
jobs:
|
||||
Fuzzing:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Build Fuzzers
|
||||
id: build
|
||||
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
|
||||
with:
|
||||
oss-fuzz-project-name: 'libusb'
|
||||
dry-run: false
|
||||
language: c
|
||||
- name: Run Fuzzers
|
||||
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
|
||||
with:
|
||||
oss-fuzz-project-name: 'libusb'
|
||||
fuzz-seconds: 600
|
||||
dry-run: false
|
||||
language: c
|
||||
- name: Upload Crash
|
||||
uses: actions/upload-artifact@v1
|
||||
if: failure() && steps.build.outcome == 'success'
|
||||
with:
|
||||
name: artifacts
|
||||
path: ./out/artifacts
|
||||
50
lib/libusb/.github/workflows/linux.yml
vendored
Normal file
50
lib/libusb/.github/workflows/linux.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
name: linux
|
||||
|
||||
# Controls when the action will run. Triggers the workflow on push or pull request
|
||||
# events but only for the master branch
|
||||
on: [push, pull_request]
|
||||
|
||||
# A workflow run is made up of one or more jobs that can run
|
||||
# sequentially or in parallel
|
||||
jobs:
|
||||
# This workflow contains a single job called "build"
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job
|
||||
# can access it
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: setup prerequisites
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install autoconf automake libtool libudev-dev m4
|
||||
|
||||
- name: bootstrap
|
||||
run: ./bootstrap.sh
|
||||
|
||||
- name: netlink
|
||||
# Disable tests for netlink as it doesn't seem to work in the CI environment.
|
||||
run: .private/ci-build.sh --build-dir build-netlink --no-test -- --disable-udev
|
||||
|
||||
- name: udev
|
||||
run: .private/ci-build.sh --build-dir build-udev -- --enable-udev
|
||||
|
||||
- name: debug-log
|
||||
run: .private/ci-build.sh --build-dir build-debug -- --enable-debug-log
|
||||
|
||||
- name: disable-log
|
||||
run: .private/ci-build.sh --build-dir build-nolog -- --disable-log
|
||||
|
||||
- uses: mymindstorm/setup-emsdk@v13
|
||||
|
||||
- run: npm ci
|
||||
working-directory: tests/webusb-test-shim
|
||||
|
||||
- name: emscripten
|
||||
run: emconfigure .private/ci-build.sh --build-dir build-emscripten -- --host=wasm32-unknown-emscripten
|
||||
|
||||
- name: umockdev test
|
||||
run: .private/ci-container-build.sh docker.io/amd64/ubuntu:rolling
|
||||
36
lib/libusb/.github/workflows/macos.yml
vendored
Normal file
36
lib/libusb/.github/workflows/macos.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
name: macOS
|
||||
|
||||
# Controls when the action will run. Triggers the workflow on push or pull request
|
||||
# events but only for the master branch
|
||||
on: [push, pull_request]
|
||||
|
||||
# A workflow run is made up of one or more jobs that can run
|
||||
# sequentially or in parallel
|
||||
jobs:
|
||||
# This workflow contains a single job called "build"
|
||||
build:
|
||||
runs-on: macos-latest
|
||||
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job
|
||||
# can access it
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: setup prerequisites
|
||||
shell: bash
|
||||
run: |
|
||||
brew update
|
||||
brew install autoconf automake libtool m4
|
||||
|
||||
- name: bootstrap
|
||||
shell: bash
|
||||
run: ./bootstrap.sh
|
||||
|
||||
- name: compile
|
||||
shell: bash
|
||||
run: .private/ci-build.sh --build-dir build
|
||||
|
||||
- name: Xcode
|
||||
shell: bash
|
||||
run: cd Xcode && xcodebuild -project libusb.xcodeproj
|
||||
23
lib/libusb/.github/workflows/msys2.yml
vendored
Normal file
23
lib/libusb/.github/workflows/msys2.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: MSYS2 build
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: MINGW64
|
||||
update: true
|
||||
install: git mingw-w64-x86_64-cc mingw-w64-x86_64-autotools
|
||||
- name: bootstrap
|
||||
run: ./bootstrap.sh
|
||||
- name: Build
|
||||
# GCC on MSYS2 doesn't have ASAN support (but Clang does).
|
||||
run: ./.private/ci-build.sh --build-dir build-msys2 --no-asan
|
||||
- name: Build with logging disabled
|
||||
run: ./.private/ci-build.sh --build-dir build-msys2-nolog --no-asan -- --disable-log
|
||||
25
lib/libusb/.github/workflows/msys2_clang32.yml
vendored
Normal file
25
lib/libusb/.github/workflows/msys2_clang32.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
name: MSYS2 clang32 build
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: clang32
|
||||
update: true
|
||||
install: git mingw-w64-clang-i686-cc mingw-w64-clang-i686-autotools
|
||||
- name: CI-Build
|
||||
run: |
|
||||
echo 'Running in MSYS2!'
|
||||
./bootstrap.sh
|
||||
# Disabling tests as there is some issue that prevents libtool from
|
||||
# finalizing its executable wrappers.
|
||||
# Perhaps this one https://github.com/msys2/MSYS2-packages/issues/1351
|
||||
# but it only occurs on clang32 configuration.
|
||||
./.private/ci-build.sh --build-dir build-msys2-clang32 --no-test
|
||||
21
lib/libusb/.github/workflows/msys2_clang64.yml
vendored
Normal file
21
lib/libusb/.github/workflows/msys2_clang64.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
name: MSYS2 clang64 build
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: clang64
|
||||
update: true
|
||||
install: git mingw-w64-clang-x86_64-cc mingw-w64-clang-x86_64-autotools
|
||||
- name: CI-Build
|
||||
run: |
|
||||
echo 'Running in MSYS2!'
|
||||
./bootstrap.sh
|
||||
./.private/ci-build.sh --build-dir build-msys2-clang64
|
||||
84
lib/libusb/.gitignore
vendored
Normal file
84
lib/libusb/.gitignore
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
.deps
|
||||
.libs
|
||||
Makefile
|
||||
Makefile.in
|
||||
!doc/Makefile.in
|
||||
*.la
|
||||
*.lo
|
||||
*.o
|
||||
*.js
|
||||
!/tests/webusb-test-shim/*.js
|
||||
*.wasm
|
||||
*.html
|
||||
libtool
|
||||
ltmain.sh
|
||||
missing
|
||||
stamp-h1
|
||||
m4/
|
||||
autom4te.cache
|
||||
INSTALL
|
||||
install-sh
|
||||
depcomp
|
||||
configure
|
||||
aclocal.m4
|
||||
compile
|
||||
test-driver
|
||||
config.guess
|
||||
config.h*
|
||||
!msvc/config.h
|
||||
!android/config.h
|
||||
!Xcode/config.h
|
||||
.vs
|
||||
config.log
|
||||
config.status
|
||||
config.sub
|
||||
*.swp
|
||||
doxygen.cfg
|
||||
examples/listdevs
|
||||
examples/xusb
|
||||
examples/dpfp
|
||||
examples/dpfp_threaded
|
||||
examples/fxload
|
||||
examples/hotplugtest
|
||||
examples/sam3u_benchmark
|
||||
examples/testlibusb
|
||||
tests/init_context
|
||||
tests/macos
|
||||
tests/set_option
|
||||
tests/stress
|
||||
tests/stress_mt
|
||||
tests/*.log
|
||||
tests/*.trs
|
||||
android/libs
|
||||
android/obj
|
||||
*.exe
|
||||
*.pc
|
||||
doc/api-1.0
|
||||
*.plg
|
||||
*.ncb
|
||||
*.opt
|
||||
Debug
|
||||
Release
|
||||
Debug-MT
|
||||
Release-MT
|
||||
*.db
|
||||
*.user
|
||||
*.suo
|
||||
*.sdf
|
||||
*.opensdf
|
||||
*.patch
|
||||
*~
|
||||
*.orig
|
||||
.dirstamp
|
||||
.amend
|
||||
.DS_Store
|
||||
Xcode/build
|
||||
xcshareddata
|
||||
xcuserdata
|
||||
*.xcuserdatad
|
||||
*.xccheckout
|
||||
*.xcscmblueprint
|
||||
*.xcworkspace
|
||||
build/
|
||||
tags
|
||||
cscope.out
|
||||
5
lib/libusb/.private/README.txt
Normal file
5
lib/libusb/.private/README.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
This directory contains private internal scripts used by the libusb
|
||||
project maintainers.
|
||||
|
||||
These scripts are not intended for general usage and will not be
|
||||
exported when producing release archives.
|
||||
26
lib/libusb/.private/appveyor_build.sh
Executable file
26
lib/libusb/.private/appveyor_build.sh
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/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 ""
|
||||
|
||||
extra_args=""
|
||||
if [ "${Configuration}" == "Release" ]; then
|
||||
extra_args="--no-asan"
|
||||
fi
|
||||
exec .private/ci-build.sh --build-dir "${builddir}" --install ${extra_args} -- "--prefix=${installdir}"
|
||||
54
lib/libusb/.private/bm.sh
Executable file
54
lib/libusb/.private/bm.sh
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/bin/sh
|
||||
# produce the MinGW binary files for snapshots
|
||||
# !!!THIS SCRIPT IS FOR INTERNAL DEVELOPER USE ONLY!!!
|
||||
|
||||
PWD=`pwd`
|
||||
cd ..
|
||||
date=`date +%Y.%m.%d`
|
||||
target=e:/dailies/$date
|
||||
mkdir -p $target/include/libusb-1.0
|
||||
cp -v libusb/libusb-1.0.def $target
|
||||
cp -v libusb/libusb.h $target/include/libusb-1.0
|
||||
|
||||
#
|
||||
# 32 bit binaries
|
||||
#
|
||||
target=e:/dailies/$date/MinGW32
|
||||
git clean -fdx
|
||||
# Not using debug (-g) in CFLAGS DRAMATICALLY reduces the size of the binaries
|
||||
export CFLAGS="-O2 -m32"
|
||||
export LDFLAGS="-m32"
|
||||
export RCFLAGS="--target=pe-i386"
|
||||
export DLLTOOLFLAGS="-m i386 -f --32"
|
||||
echo `pwd`
|
||||
(glibtoolize --version) < /dev/null > /dev/null 2>&1 && LIBTOOLIZE=glibtoolize || LIBTOOLIZE=libtoolize
|
||||
$LIBTOOLIZE --copy --force || exit 1
|
||||
aclocal || exit 1
|
||||
autoheader || exit 1
|
||||
autoconf || exit 1
|
||||
automake -a -c || exit 1
|
||||
./configure
|
||||
make -j2
|
||||
mkdir -p $target/static
|
||||
mkdir -p $target/dll
|
||||
cp -v libusb/.libs/libusb-1.0.a $target/static
|
||||
cp -v libusb/.libs/libusb-1.0.dll $target/dll
|
||||
cp -v libusb/.libs/libusb-1.0.dll.a $target/dll
|
||||
make clean -j2
|
||||
|
||||
#
|
||||
# 64 bit binaries
|
||||
#
|
||||
target=e:/dailies/$date/MinGW64
|
||||
export CFLAGS="-O2"
|
||||
export LDFLAGS=""
|
||||
export RCFLAGS=""
|
||||
export DLLTOOLFLAGS=""
|
||||
./configure
|
||||
make -j2
|
||||
mkdir -p $target/static
|
||||
mkdir -p $target/dll
|
||||
cp -v libusb/.libs/libusb-1.0.a $target/static
|
||||
cp -v libusb/.libs/libusb-1.0.dll $target/dll
|
||||
cp -v libusb/.libs/libusb-1.0.dll.a $target/dll
|
||||
cd $PWD
|
||||
92
lib/libusb/.private/ci-build.sh
Executable file
92
lib/libusb/.private/ci-build.sh
Executable file
@@ -0,0 +1,92 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
builddir=
|
||||
scriptdir=$(dirname $(readlink -f "$0"))
|
||||
install=no
|
||||
test=yes
|
||||
asan=yes
|
||||
|
||||
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
|
||||
;;
|
||||
--no-test)
|
||||
test=no
|
||||
shift
|
||||
;;
|
||||
--no-asan)
|
||||
asan=no
|
||||
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"
|
||||
|
||||
# enable address sanitizer
|
||||
if [ "${asan}" = "yes" ]; then
|
||||
cflags+=" -fsanitize=address"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Configuring ..."
|
||||
CFLAGS="${cflags}" CXXFLAGS="${cflags}" ../configure --enable-examples-build --enable-tests-build "$@"
|
||||
|
||||
echo ""
|
||||
echo "Building ..."
|
||||
make -j4 -k
|
||||
|
||||
if [ "${test}" = "yes" ]; then
|
||||
# Load custom shim for WebUSB tests that simulates Web environment.
|
||||
export NODE_OPTIONS="--require ${scriptdir}/../tests/webusb-test-shim/"
|
||||
if ! make check ; then
|
||||
cat tests/test-suite.log
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "${install}" = "yes" ]; then
|
||||
echo ""
|
||||
echo "Installing ..."
|
||||
make install
|
||||
fi
|
||||
67
lib/libusb/.private/ci-container-build.sh
Executable file
67
lib/libusb/.private/ci-container-build.sh
Executable file
@@ -0,0 +1,67 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
|
||||
# keep container around if $DEBUG is set
|
||||
[ -n "${DEBUG:-}" ] || OPTS="--rm"
|
||||
|
||||
if type podman >/dev/null 2>&1; then
|
||||
RUNC=podman
|
||||
else
|
||||
RUNC="sudo docker"
|
||||
fi
|
||||
|
||||
MOUNT_MODE=":ro"
|
||||
|
||||
$RUNC run --interactive ${RUNC_OPTIONS:-} ${OPTS:-} --volume `pwd`:/source${MOUNT_MODE:-} ${1:-docker.io/amd64/ubuntu:rolling} /bin/bash << EOF
|
||||
set -ex
|
||||
|
||||
# avoid meson exit code 125; https://github.com/containers/podman/issues/11540
|
||||
trap '[ \$? -eq 0 ] || exit 1' EXIT
|
||||
|
||||
# go-faster apt
|
||||
echo 'Acquire::Languages "none";' > /etc/apt/apt.conf.d/90nolanguages
|
||||
|
||||
# upgrade
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update
|
||||
apt-get install -y eatmydata
|
||||
eatmydata apt-get -y --purge dist-upgrade
|
||||
|
||||
# install build and test dependencies
|
||||
eatmydata apt-get install -y make libtool libudev-dev pkg-config umockdev libumockdev-dev
|
||||
|
||||
# run build as user
|
||||
useradd build
|
||||
su -s /bin/bash - build << EOG
|
||||
set -ex
|
||||
|
||||
mkdir "/tmp/builddir"
|
||||
cd "/tmp/builddir"
|
||||
|
||||
CFLAGS="-O2"
|
||||
|
||||
# enable extra warnings
|
||||
CFLAGS+=" -Winline"
|
||||
CFLAGS+=" -Wmissing-include-dirs"
|
||||
CFLAGS+=" -Wnested-externs"
|
||||
CFLAGS+=" -Wpointer-arith"
|
||||
CFLAGS+=" -Wredundant-decls"
|
||||
CFLAGS+=" -Wswitch-enum"
|
||||
export CFLAGS
|
||||
|
||||
export CXXFLAGS="\${CFLAGS}"
|
||||
|
||||
echo ""
|
||||
echo "Configuring ..."
|
||||
/source/configure --enable-examples-build --enable-tests-build
|
||||
|
||||
echo ""
|
||||
echo "Building ..."
|
||||
make -j4 -k
|
||||
|
||||
echo ""
|
||||
echo "Running umockdev tests ..."
|
||||
tests/umockdev
|
||||
EOG
|
||||
EOF
|
||||
32
lib/libusb/.private/post-rewrite.sh
Executable file
32
lib/libusb/.private/post-rewrite.sh
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Detect amended commits and warn user if .amend is missing
|
||||
#
|
||||
# To have git run this script on commit, create a "post-rewrite" text file in
|
||||
# .git/hooks/ with the following content:
|
||||
# #!/bin/sh
|
||||
# if [ -x .private/post-rewrite.sh ]; then
|
||||
# . .private/post-rewrite.sh
|
||||
# fi
|
||||
#
|
||||
# NOTE: These versioning hooks are intended to be used *INTERNALLY* by the
|
||||
# libusb development team and are NOT intended to solve versioning for any
|
||||
# derivative branch, such as one you would create for private development.
|
||||
#
|
||||
|
||||
if [ -n "$LIBUSB_SKIP_NANO" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
case "$1" in
|
||||
amend)
|
||||
# Check if a .amend exists. If none, create one and warn user to re-commit.
|
||||
if [ -f .amend ]; then
|
||||
rm .amend
|
||||
else
|
||||
echo "Amend commit detected, but no .amend file - One has now been created."
|
||||
echo "Please re-commit as is (amend), so that the version number is correct."
|
||||
touch .amend
|
||||
fi ;;
|
||||
*) ;;
|
||||
esac
|
||||
52
lib/libusb/.private/pre-commit.sh
Executable file
52
lib/libusb/.private/pre-commit.sh
Executable file
@@ -0,0 +1,52 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Sets the nano version according to the number of commits on this branch, as
|
||||
# well as the branch offset.
|
||||
#
|
||||
# To have git run this script on commit, first make sure you change
|
||||
# BRANCH_OFFSET to 60000 or higher, then create a "pre-commit" text file in
|
||||
# .git/hooks/ with the following content:
|
||||
# #!/bin/sh
|
||||
# if [ -x .private/pre-commit.sh ]; then
|
||||
# . .private/pre-commit.sh
|
||||
# fi
|
||||
#
|
||||
# NOTE: These versioning hooks are intended to be used *INTERNALLY* by the
|
||||
# libusb development team and are NOT intended to solve versioning for any
|
||||
# derivative branch, such as one you would create for private development.
|
||||
#
|
||||
# Should you wish to reuse these scripts for your own versioning, in your own
|
||||
# private branch, we kindly ask you to first set BRANCH_OFFSET to 60000, or
|
||||
# higher, as any offset below below 60000 is *RESERVED* for libusb official
|
||||
# usage.
|
||||
|
||||
################################################################################
|
||||
## YOU *MUST* SET THE FOLLOWING TO 60000 OR HIGHER IF YOU REUSE THIS SCRIPT ##
|
||||
################################################################################
|
||||
BRANCH_OFFSET=10000
|
||||
################################################################################
|
||||
|
||||
if [ -n "$LIBUSB_SKIP_NANO" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$BASH_VERSION" = '' ]; then
|
||||
TYPE_CMD="type git >/dev/null 2>&1"
|
||||
else
|
||||
TYPE_CMD="type -P git &>/dev/null"
|
||||
fi
|
||||
|
||||
eval $TYPE_CMD || { echo "git command not found. Aborting." >&2; exit 1; }
|
||||
|
||||
NANO=`git log --oneline | wc -l`
|
||||
NANO=`expr $NANO + $BRANCH_OFFSET`
|
||||
# Amended commits need to have the nano corrected. Current versions of git hooks
|
||||
# only allow detection of amending post commit, so we require a .amend file,
|
||||
# which will be created post commit with a user warning if none exists when an
|
||||
# amend is detected.
|
||||
if [ -f .amend ]; then
|
||||
NANO=`expr $NANO - 1`
|
||||
fi
|
||||
echo "setting nano to $NANO"
|
||||
echo "#define LIBUSB_NANO $NANO" > libusb/version_nano.h
|
||||
git add libusb/version_nano.h
|
||||
43
lib/libusb/.private/wbs.txt
Normal file
43
lib/libusb/.private/wbs.txt
Normal file
@@ -0,0 +1,43 @@
|
||||
libusb 1.0 Windows binary snapshot - README
|
||||
|
||||
*********************************************************************
|
||||
* The latest version of this snapshot can always be downloaded at: *
|
||||
* https://github.com/libusb/libusb/releases *
|
||||
*********************************************************************
|
||||
|
||||
o Visual Studio:
|
||||
- Open existing or create a new project for your application
|
||||
- Copy libusb.h, from the include\libusb-1.0\ directory, into your project and
|
||||
make sure that the location where the file reside appears in the 'Additional
|
||||
Include Directories' section (Configuration Properties -> C/C++ -> General).
|
||||
- Copy the relevant .lib file from MS32\ or MS64\ and add 'libusb-1.0.lib' to
|
||||
your 'Additional Dependencies' (Configuration Properties -> Linker -> Input)
|
||||
Also make sure that the directory where libusb-1.0.lib resides is added to
|
||||
'Additional Library Directories' (Configuration Properties -> Linker
|
||||
-> General)
|
||||
- By default, static libusb statically links against the CRT and the dll build
|
||||
dynamically links against CRT. You need to rebuild libusb from source to
|
||||
change this if required by your application.
|
||||
- Compile and run your application. If you use the DLL version of libusb-1.0,
|
||||
remember that the DLL needs to be in the DLL search path of your application.
|
||||
|
||||
o MinGW/cygwin
|
||||
- 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.
|
||||
Or, if you don't want to use the default locations, make sure that you feed
|
||||
the relevant -I and -L options to the compiler.
|
||||
- Add the '-lusb-1.0' linker option when compiling.
|
||||
|
||||
o Additional information:
|
||||
- The libusb 1.0 API documentation can be accessed at:
|
||||
http://api.libusb.info
|
||||
- For some libusb samples (including source), please have a look in examples/
|
||||
- For additional information on the libusb 1.0 Windows backend please visit:
|
||||
http://windows.libusb.info
|
||||
- Using the UsbDk backend is now a run-time choice rather than a compile-time
|
||||
choice. For additional information, including example usage, please visit:
|
||||
http://windows.libusb.info/#Driver_Installation
|
||||
- The MinGW and MS generated DLLs are fully interchangeable, provided that you
|
||||
use the import libs provided or generate one from the .def also provided.
|
||||
- If you find any issue, please visit https://libusb.info/ and check the
|
||||
Support section
|
||||
58
lib/libusb/.travis.yml
Normal file
58
lib/libusb/.travis.yml
Normal file
@@ -0,0 +1,58 @@
|
||||
language: c
|
||||
|
||||
git:
|
||||
depth: 1
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
dist: focal
|
||||
compiler: clang
|
||||
- os: linux
|
||||
dist: focal
|
||||
compiler: gcc
|
||||
- os: linux
|
||||
dist: bionic
|
||||
compiler: clang
|
||||
- os: linux
|
||||
dist: bionic
|
||||
compiler: gcc
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: clang
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: gcc
|
||||
- os: osx
|
||||
osx_image: xcode12.2
|
||||
compiler: clang
|
||||
- os: osx
|
||||
osx_image: xcode11.3
|
||||
compiler: clang
|
||||
- os: osx
|
||||
osx_image: xcode9.4
|
||||
compiler: clang
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- autoconf
|
||||
- automake
|
||||
- libtool
|
||||
- libudev-dev
|
||||
- m4
|
||||
homebrew:
|
||||
packages:
|
||||
- autoconf
|
||||
- automake
|
||||
- libtool
|
||||
- m4
|
||||
|
||||
before_script:
|
||||
- ./bootstrap.sh
|
||||
|
||||
script:
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then .private/ci-build.sh --build-dir build-netlink -- --disable-udev; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then .private/ci-build.sh --build-dir build-udev -- --enable-udev; 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
|
||||
224
lib/libusb/AUTHORS
Normal file
224
lib/libusb/AUTHORS
Normal file
@@ -0,0 +1,224 @@
|
||||
Copyright © 2001 Johannes Erdfelt <johannes@erdfelt.com>
|
||||
Copyright © 2007-2009 Daniel Drake <dsd@gentoo.org>
|
||||
Copyright © 2010-2012 Peter Stuge <peter@stuge.se>
|
||||
Copyright © 2008-2016 Nathan Hjelm <hjelmn@users.sourceforge.net>
|
||||
Copyright © 2009-2013 Pete Batard <pete@akeo.ie>
|
||||
Copyright © 2009-2013 Ludovic Rousseau <ludovic.rousseau@gmail.com>
|
||||
Copyright © 2010-2012 Michael Plante <michael.plante@gmail.com>
|
||||
Copyright © 2011-2013 Hans de Goede <hdegoede@redhat.com>
|
||||
Copyright © 2012-2013 Martin Pieuchot <mpi@openbsd.org>
|
||||
Copyright © 2012-2013 Toby Gray <toby.gray@realvnc.com>
|
||||
Copyright © 2013-2018 Chris Dickens <christopher.a.dickens@gmail.com>
|
||||
|
||||
Other contributors:
|
||||
Aaron Luft
|
||||
Adam Korcz
|
||||
Addison Crump
|
||||
Adrian Bunk
|
||||
Adrien Destugues
|
||||
Akshay Jaggi
|
||||
Alan Ott
|
||||
Alan Stern
|
||||
Aleksandr Mezin
|
||||
Alexander Mot
|
||||
Alexander Pyhalov
|
||||
Alexander Schlarb
|
||||
Alexander Stein
|
||||
Alex Feinman
|
||||
Alex Vatchenko
|
||||
Andrew Aldridge
|
||||
Andrew Fernandes
|
||||
Andrew Goodney
|
||||
Andy Chunyu
|
||||
Andy McFadden
|
||||
Angus Gratton
|
||||
Anil Nair
|
||||
Ankur Verma
|
||||
Anthony Clay
|
||||
Antonio Ospite
|
||||
Artem Egorkine
|
||||
Aurelien Jarno
|
||||
Axel Gembe
|
||||
Aymeric Vincent
|
||||
Baruch Siach
|
||||
Bastien Nocera
|
||||
Bei Zhang
|
||||
Bence Csokas
|
||||
Benjamin Berg
|
||||
Benjamin Dobell
|
||||
Bohdan Tymkiv
|
||||
Brad Smith
|
||||
Brent Rector
|
||||
Bruno Harbulot
|
||||
Carl Karsten
|
||||
Christophe Zeitouny
|
||||
Chris Zhu
|
||||
Chunyu Xie
|
||||
Colin Walters
|
||||
Craig Hutchinson
|
||||
Dave Camarillo
|
||||
David Engraf
|
||||
Davidlohr Bueso
|
||||
David Moore
|
||||
Dmitry Fleytman
|
||||
Dmitry Kostjuchenko
|
||||
Dmitry Zakablukov
|
||||
Dominik Boehi
|
||||
Doug Johnston
|
||||
Edgar Fuß
|
||||
Evan Hunter
|
||||
Evan Miller
|
||||
Fabrice Fontaine
|
||||
Federico Manzan
|
||||
Felipe Balbi
|
||||
Florian Albrechtskirchinger
|
||||
Francesco Montorsi
|
||||
Francisco Facioni
|
||||
Francis Hart
|
||||
Frank Li
|
||||
Frederik Carlier
|
||||
Freek Dijkstra
|
||||
Gaurav Gupta
|
||||
Graeme Gill
|
||||
Greg Kroah-Hartman
|
||||
Gustavo Zacarias
|
||||
Haidong Zheng
|
||||
Hans Ulrich Niedermann
|
||||
Harry Mallon
|
||||
Hector Martin
|
||||
Hoi-Ho Chan
|
||||
Ido Yariv
|
||||
Igor Anokhin
|
||||
Ihor Dutchak
|
||||
Ilya Konstantinov
|
||||
Ingvar Stepanyan
|
||||
Jakub Klama
|
||||
James Hanko
|
||||
Jeffrey Nichols
|
||||
Jie Zhang
|
||||
Jim Chen
|
||||
Johann Richard
|
||||
John Keeping
|
||||
John Sheu
|
||||
Jonas Malaco
|
||||
Jonathon Jongsma
|
||||
Joost Muller
|
||||
Josh Gao
|
||||
Joshua Blake
|
||||
Joshua Hou
|
||||
Joshua M. Clulow
|
||||
Juan Cruz Viotti
|
||||
Julian Scheel
|
||||
Justin Bischoff
|
||||
Karsten Koenig
|
||||
Keith Ahluwalia
|
||||
Kenjiro Tsuji
|
||||
Kimura Masaru
|
||||
Konrad Rzepecki
|
||||
Kuangye Guo
|
||||
Lars Kanis
|
||||
Lars Wirzenius
|
||||
Lei Chen
|
||||
Léo Lam
|
||||
Liang Yunwang
|
||||
Lonnie Abelbeck
|
||||
Luca Longinotti
|
||||
Luz Paz
|
||||
Mac Wang
|
||||
Marco Trevisan (Treviño)
|
||||
Marcus Meissner
|
||||
Mario Kleiner
|
||||
Mark Kuo
|
||||
Markus Heidelberg
|
||||
Martin Ettl
|
||||
Martin Koegler
|
||||
Martin Ling
|
||||
Martin Thierer
|
||||
Mathias Hjärtström
|
||||
Matthew Stapleton
|
||||
Matthias Bolte
|
||||
Michael Dickens
|
||||
Michel Zou
|
||||
Mike Frysinger
|
||||
Mikhail Gusarov
|
||||
Mikolaj Kucharski
|
||||
Morgan Leborgne
|
||||
Moritz Fischer
|
||||
Nancy Li
|
||||
Nia Alarie
|
||||
Nicholas Corgan
|
||||
Niklas Gürtler
|
||||
Omri Iluz
|
||||
Orhan aib Kavrakoglu
|
||||
Orin Eman
|
||||
Ozkan Sezer
|
||||
Pablo Prietz
|
||||
Patrick Stewart
|
||||
Paul Cercueil
|
||||
Paul Fertser
|
||||
Paul Qureshi
|
||||
Pekka Nikander
|
||||
Petr Pazourek
|
||||
Philémon Favrod
|
||||
Pino Toscano
|
||||
Rob Walker
|
||||
Romain Vimont
|
||||
Roman Kalashnikov
|
||||
Rosen Penev
|
||||
Ryan Hileman
|
||||
Ryan Metcalfe
|
||||
Ryan Schmidt
|
||||
Saleem Rashid
|
||||
Sameeh Jubran
|
||||
Sean McBride
|
||||
Sebastian Pipping
|
||||
Sebastian von Ohr
|
||||
Sergey Serb
|
||||
Shawn Hoffman
|
||||
Simon Chan
|
||||
Simon Haggett
|
||||
Simon Newton
|
||||
Slash Gordon
|
||||
Stefan Agner
|
||||
Stefan Tauner
|
||||
Steinar H. Gunderson
|
||||
Stephen Groat
|
||||
Sylvain Fasel
|
||||
Theo Buehler
|
||||
Thomas Röfer
|
||||
Tim Hutt
|
||||
Tim Roberts
|
||||
Tobias Klauser
|
||||
Toby Peterson
|
||||
Tormod Volden
|
||||
Trygve Laugstøl
|
||||
Uri Lublin
|
||||
Uwe Bonnes
|
||||
Vasily Khoruzhick
|
||||
Vegard Storheil Eriksen
|
||||
Venkatesh Shukla
|
||||
Vianney le Clément de Saint-Marcq
|
||||
Victor Toso
|
||||
Vinicius Tinti
|
||||
Vitali Lovich
|
||||
Vladimir Beloborodov
|
||||
William Orr
|
||||
William Skellenger
|
||||
Xiaofan Chen
|
||||
Yegor Yefremov
|
||||
Zeng Guang
|
||||
Zhiqiang Liu
|
||||
Zoltán Kovács
|
||||
Сергей Валерьевич
|
||||
Ларионов Даниил
|
||||
Роман Донченко
|
||||
jonner
|
||||
orbitcowboy
|
||||
osy
|
||||
parafin
|
||||
RipleyTom
|
||||
Seneral
|
||||
saur0n
|
||||
SomeAlphabetGuy
|
||||
winterrace
|
||||
xloem
|
||||
504
lib/libusb/COPYING
Normal file
504
lib/libusb/COPYING
Normal file
@@ -0,0 +1,504 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
||||
|
||||
351
lib/libusb/ChangeLog
Normal file
351
lib/libusb/ChangeLog
Normal file
@@ -0,0 +1,351 @@
|
||||
For detailed information about the changes below, please see the git log
|
||||
or visit: http://log.libusb.info
|
||||
|
||||
2024-01-31: v1.0.27
|
||||
* New libusb_init_context API to replace libusb_init
|
||||
* New libusb_get_max_alt_packet_size API
|
||||
* New libusb_get_platform_descriptor API (BOS)
|
||||
* Allow setting log callback with libusb_set_option/libusb_init_context
|
||||
* New WebAssembly + WebUSB backend using Emscripten
|
||||
* Fix regression in libusb_set_interface_alt_setting
|
||||
* Fix sync transfer completion race and use-after-free
|
||||
* Fix hotplug exit ordering
|
||||
* Linux: NO_DEVICE_DISCOVERY option set per context
|
||||
* macOS: Fix missing device list cleanup locking
|
||||
* macOS: Do not clear device data toggle for newer OS versions
|
||||
* macOS: Fix running binaries on older OS than build host
|
||||
* Windows: Allow claiming multiple associated interfaces
|
||||
* Windows: Ignore non-configured devices instead of waiting
|
||||
* Windows: Improved root hub detection
|
||||
|
||||
2022-04-10: v1.0.26
|
||||
* Fix regression with transfer free's after closing device
|
||||
* Fix regression with destroyed context if API is misused
|
||||
* Workaround for applications using missing default context
|
||||
* Fix hotplog enumeration regression
|
||||
* Fix Windows isochronous transfer regression since 1.0.24
|
||||
* Fix macOS exit crash in some multi-context cases
|
||||
* Build fixes for various platforms and configurations
|
||||
* Fix Windows HID multi-interface product string retrieval
|
||||
* Update isochronous OUT packet actual lengths on Windows
|
||||
* Add interface bound checking for broken devices
|
||||
* Add umockdev tests on Linux
|
||||
|
||||
2022-01-31: v1.0.25
|
||||
* Linux: Fix regression with some particular devices
|
||||
* Linux: Fix regression with libusb_handle_events_timeout_completed()
|
||||
* Linux: Fix regression with cpu usage in libusb_bulk_transfer
|
||||
* Darwin (macOS): Add support for detaching kernel drivers with authorization.
|
||||
* Darwin (macOS): Do not drop partial data on timeout.
|
||||
* Darwin (macOS): Silence pipe error in set_interface_alt_setting().
|
||||
* Windows: Fix HID backend missing byte
|
||||
* Windows: Fix segfault with libusbk driver
|
||||
* Windows: Fix regression when using libusb0 driver
|
||||
* Windows: Support LIBUSB_TRANSFER_ADD_ZERO_PACKET on winusb
|
||||
* New NO_DEVICE_DISCOVERY option replaces WEAK_AUTHORITY option
|
||||
* Various other bug fixes and improvements
|
||||
|
||||
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 URBs have been reaped before freeing them (#607)
|
||||
* NetBSD: Recognize device timeouts (#710)
|
||||
* OpenBSD: Allow opening ugen devices multiple times (#763)
|
||||
* OpenBSD: Support libusb_get_port_number() (#764)
|
||||
* SunOS: Fix a memory leak (#756)
|
||||
* SunOS: Various fixes (#627, #628, #629)
|
||||
* Windows: Add Visual Studio 2019 support
|
||||
* Windows: Drop support for WinCE and Visual Studio older than 2013
|
||||
* Windows: Drop support for Windows XP
|
||||
* Windows: Support building all examples using Visual Studio (#151)
|
||||
* Documentation fixes and improvements
|
||||
* Various other bug fixes and improvements
|
||||
|
||||
2019-08-28: v1.0.23
|
||||
* Add German translation (#446)
|
||||
* Add Hungarian translation (#493)
|
||||
* Android: Improved support for Android
|
||||
* BSD: Remove infinite recursion in OpenBSD backend
|
||||
* configure.ac: Fix detection of clock_gettime library (#439)
|
||||
* Core: abandon synchronous transfers when device closure is detected.
|
||||
* Core: fix error in handling the removal of file descriptors while handling
|
||||
events.
|
||||
* Darwin(macOS): Switch from using ResetDevice to USBDeviceReEnumerate (#455)
|
||||
* Darwin(macOS): Remove code that changed the device class used (#428)
|
||||
* Darwin(macOS): Reduce hotplug timeout to 1ms (from 5s)
|
||||
* New API libusb_set_log_cb() to redirect global and per context log
|
||||
messages to the provided log handling function
|
||||
* New API libusb_wrap_sys_device to allow the user to specify the
|
||||
usb device to use.
|
||||
* Solaris: Break infinite recursion in backend clock_gettime
|
||||
* Solaris: Enable timerfd on sunos when available
|
||||
* Windows: Add support for isochronous transfers with WinUSB
|
||||
* Various other bug fixes and improvements
|
||||
|
||||
2018-03-24: v1.0.22
|
||||
* New libusb_set_option() API
|
||||
* Fix transfer timeout not being cleared upon resubmission
|
||||
* Report super speed plus devices on modern Linux and macOS
|
||||
* Darwin: Improve support for macOS Sierra and High Sierra
|
||||
* Darwin: SDK fixes and improvements
|
||||
* Linux: Let initialization succeed when no devices are present
|
||||
* Linux: Mark internal file descriptors with CLOEXEC flag
|
||||
* Solaris: Add support for attach/detach kernel driver
|
||||
* Windows: Add dynamic UsbDk backend selection
|
||||
* Windows: Add isochronous transfer support via libusbK
|
||||
* Windows: Add Visual Studio 2017 support
|
||||
* Windows: Fix enumeration problems on Windows 8 and later
|
||||
* Windows: Major rework of poll() emulation
|
||||
* Windows: Numerous HID API fixes
|
||||
* Windows: Support cancellation of individual transfers (Vista and later)
|
||||
* Various other bug fixes and improvements
|
||||
|
||||
2016-10-01: v1.0.21
|
||||
* Core: Refactor code related to transfer flags and timeout handling
|
||||
* Darwin: Ignore root hub simulation devices
|
||||
* Darwin: Improved support for OS X El Capitan
|
||||
* Darwin: Work around devices with buggy endpoint descriptors
|
||||
* Darwin: Do not use objc_registerThreadWithCollector after its deprecation
|
||||
* Darwin: Use C11 atomics on 10.12+ as the OS atomics are now deprecated
|
||||
* Linux: Support preallocating kernel memory for zerocopy USB
|
||||
* Linux: Deal with receiving POLLERR before all transfers have completed
|
||||
* Solaris: Add solaris backend
|
||||
* Windows: Add Visual Studio 2015 support
|
||||
* Windows: Add usbdk backend
|
||||
* Prevent attempts to recursively handle events
|
||||
* Fix race condition in handle_timeout()
|
||||
* Allow transferred argument to be optional in bulk APIs
|
||||
* Various other bug fixes and improvements
|
||||
|
||||
2015-09-13: v1.0.20
|
||||
* Add Haiku support
|
||||
* Fix multiple memory and resource leaks (#16, #52, #76, #81)
|
||||
* Fix possible deadlock when executing transfer callback
|
||||
* New libusb_free_pollfds() API
|
||||
* Darwin: Fix devices not being detected on OS X 10.8 (#48)
|
||||
* Linux: Allow larger isochronous transfer submission (#23)
|
||||
* Windows: Fix broken builds Cygwin/MinGW builds and compiler warnings
|
||||
* Windows: Fix broken bus number lookup
|
||||
* Windows: Improve submission of control requests for composite devices
|
||||
* Examples: Add two-stage load support to fxload (#12)
|
||||
* Correctly report cancellations due to timeouts
|
||||
* Improve efficiency of event handling
|
||||
* Improve speed of transfer submission in multi-threaded environments
|
||||
* Various other bug fixes and improvements
|
||||
The (#xx) numbers are libusb issue numbers, see ie:
|
||||
https://github.com/libusb/libusb/issues/16
|
||||
|
||||
2014-05-30: v1.0.19
|
||||
* Add support for USB bulk streams on Linux and Mac OS X (#11)
|
||||
* Windows: Add AMD and Intel USB-3.0 root hub support
|
||||
* Windows: Fix USB 3.0 speed detection on Windows 8 or later (#10)
|
||||
* Added Russian translation for libusb_strerror strings
|
||||
* All: Various small fixes and cleanups
|
||||
|
||||
2014-01-25: v1.0.18
|
||||
* Fix multiple memory leaks
|
||||
* Fix a crash when HID transfers return no data on Windows
|
||||
* Ensure all pending events are consumed
|
||||
* Improve Android and ucLinux support
|
||||
* Multiple Windows improvements (error logging, VS2013, VIA xHCI support)
|
||||
* Multiple OS X improvements (broken compilation, SIGFPE, 64bit support)
|
||||
|
||||
2013-09-06: v1.0.17
|
||||
* Hotplug callbacks now always get passed a libusb_context, even if it is
|
||||
the default context. Previously NULL would be passed for the default context,
|
||||
but since the first context created is the default context, and most apps
|
||||
use only 1 context, this meant that apps explicitly creating a context would
|
||||
still get passed NULL
|
||||
* Android: Add .mk files to build with the Android NDK
|
||||
* Darwin: Add Xcode project
|
||||
* Darwin: Fix crash on unplug (#121)
|
||||
* Linux: Fix hang (deadlock) on libusb_exit
|
||||
* Linux: Fix libusb build failure with --disable-udev (#124)
|
||||
* Linux: Fix libusb_get_device_list() hang with --disable-udev (#130)
|
||||
* OpenBSD: Update OpenBSD backend with support for control transfers to
|
||||
non-ugen(4) devices and make get_configuration() no longer generate I/O.
|
||||
Note that using this libusb version on OpenBSD requires using
|
||||
OpenBSD 5.3-current or later. Users of older OpenBSD versions are advised
|
||||
to stay with the libusb shipped with OpenBSD (mpi)
|
||||
* Windows: fix libusb_dll_2010.vcxproj link errors (#129)
|
||||
* Various other bug fixes and improvements
|
||||
|
||||
2013-07-11: v1.0.16
|
||||
* Add hotplug support for Darwin and Linux (#9)
|
||||
* Add superspeed endpoint companion descriptor support (#15)
|
||||
* Add BOS descriptor support (#15)
|
||||
* Make descriptor parsing code more robust
|
||||
* New libusb_get_port_numbers API, this is libusb_get_port_path without
|
||||
the unnecessary context parameter, libusb_get_port_path is now deprecated
|
||||
* New libusb_strerror API (#14)
|
||||
* New libusb_set_auto_detach_kernel_driver API (#17)
|
||||
* Improve topology API docs (#95)
|
||||
* Logging now use a single write call per log-message, avoiding log-message
|
||||
"interlacing" when using multiple threads.
|
||||
* Android: use Android logging when building on Android (#101)
|
||||
* Darwin: make libusb_reset reenumerate device on descriptors change (#89)
|
||||
* Darwin: add support for the LIBUSB_TRANSFER_ADD_ZERO_PACKET flag (#91)
|
||||
* Darwin: add a device cache (#112, #114)
|
||||
* Examples: Add sam3u_benchmark isochronous example by Harald Welte (#109)
|
||||
* Many other bug fixes and improvements
|
||||
The (#xx) numbers are libusbx issue numbers, see ie:
|
||||
https://github.com/libusbx/libusbx/issues/9
|
||||
|
||||
2013-04-15: v1.0.15
|
||||
* Improve transfer cancellation and avoid short read failures on broken descriptors
|
||||
* Filter out 8-bit characters in libusb_get_string_descriptor_ascii()
|
||||
* Add WinCE support
|
||||
* Add library stress tests
|
||||
* Add Cypress FX3 firmware upload support for fxload sample
|
||||
* Add HID and kernel driver detach support capabilities detection
|
||||
* Add SuperSpeed detection on OS X
|
||||
* Fix bInterval value interpretation on OS X
|
||||
* Fix issues with autoclaim, composite HID devices, interface autoclaim and
|
||||
early abort in libusb_close() on Windows. Also add VS2012 solution files.
|
||||
* Improve fd event handling on Linux
|
||||
* Other bug fixes and improvements
|
||||
|
||||
2012-09-26: v1.0.14
|
||||
* Reverts the previous API change with regards to bMaxPower.
|
||||
If this doesn't matter to you, you are encouraged to keep using v1.0.13,
|
||||
as it will use the same attribute as v2.0, to be released soon.
|
||||
* Note that LIBUSB_API_VERSION is *decreased* to 0x010000FF and the previous
|
||||
guidelines with regards to concurrent use of MaxPower/bMaxPower still apply.
|
||||
|
||||
2012-09-20: v1.0.13
|
||||
* [MAJOR] Fix a typo in the API with struct libusb_config_descriptor where
|
||||
MaxPower was used instead of bMaxPower, as defined in the specs. If your
|
||||
application was accessing the MaxPower attribute, and you need to maintain
|
||||
compatibility with libusb or older versions, see APPENDIX A below.
|
||||
* Fix broken support for the 0.1 -> 1.0 libusb-compat layer
|
||||
* Fix unwanted cancellation of pending timeouts as well as major timeout related bugs
|
||||
* Fix handling of HID and composite devices on Windows
|
||||
* Introduce LIBUSB_API_VERSION macro
|
||||
* Add Cypress FX/FX2 firmware upload sample, based on fxload from
|
||||
http://linux-hotplug.sourceforge.net
|
||||
* Add libusb0 (libusb-win32) and libusbK driver support on Windows. Note that while
|
||||
the drivers allow it, isochronous transfers are not supported yet in libusb. Also
|
||||
not supported yet is the use of libusb-win32 filter drivers on composite interfaces
|
||||
* Add support for the new get_capabilities ioctl on Linux and avoid unnecessary
|
||||
splitting of bulk transfers
|
||||
* Improve support for newer Intel and Renesas USB 3.0 controllers on Windows
|
||||
* Harmonize the device number for root hubs across platforms
|
||||
* Other bug fixes and improvements
|
||||
|
||||
2012-06-15: v1.0.12
|
||||
* Fix a potential major regression with pthread on Linux
|
||||
* Fix missing thread ID from debug log output on cygwin
|
||||
* Fix possible crash when using longjmp and MinGW's gcc 4.6
|
||||
* Add topology calls: libusb_get_port_number(), libusb_get_parent() & libusb_get_port_path()
|
||||
* Add toggleable debug, using libusb_set_debug() or the LIBUSB_DEBUG environment variable
|
||||
* Define log levels in libusb.h and set timestamp origin to first libusb_init() call
|
||||
* All logging is now sent to to stderr (info was sent to stdout previously)
|
||||
* Update log messages severity and avoid polluting log output on OS-X
|
||||
* Add HID driver support on Windows
|
||||
* Enable interchangeability of MSVC and MinGW DLLs
|
||||
* Additional bug fixes and improvements
|
||||
|
||||
2012-05-08: v1.0.11
|
||||
* Revert removal of critical Windows event handling that was introduced in 1.0.10
|
||||
* Fix a possible deadlock in Windows when submitting transfers
|
||||
* Add timestamped logging
|
||||
* Add NetBSD support (experimental) and BSD libusb_get_device_speed() data
|
||||
* Add bootstrap.sh alongside autogen.sh (bootstrap.sh doesn't invoke configure)
|
||||
* Search for device nodes in /dev for Android support
|
||||
* Other bug fixes
|
||||
|
||||
2012-04-17: v1.0.10
|
||||
* Public release
|
||||
* Add libusb_get_version
|
||||
* Add Visual Studio 2010 project files
|
||||
* Some Windows code cleanup
|
||||
* Fix xusb sample warnings
|
||||
|
||||
2012-04-02: v1.0.9
|
||||
* First libusbx release
|
||||
* Add libusb_get_device_speed (all, except BSD) and libusb_error_name
|
||||
* Add Windows support (WinUSB driver only)
|
||||
* Add OpenBSD support
|
||||
* Add xusb sample
|
||||
* Tons of bug fixes
|
||||
|
||||
2010-05-07: v1.0.8
|
||||
* Bug fixes
|
||||
|
||||
2010-04-19: v1.0.7
|
||||
* Bug fixes and documentation tweaks
|
||||
* Add more interface class definitions
|
||||
|
||||
2009-11-22: v1.0.6
|
||||
* Bug fixes
|
||||
* Increase libusb_handle_events() timeout to 60s for powersaving
|
||||
|
||||
2009-11-15: v1.0.5
|
||||
* Use timerfd when available for timer management
|
||||
* Small fixes/updates
|
||||
|
||||
2009-11-06: v1.0.4 release
|
||||
* Bug fixes including transfer locking to fix some potential threading races
|
||||
* More flexibility with clock types on Linux
|
||||
* Use new bulk continuation tracking in Linux 2.6.32 for improved handling
|
||||
of short/failed transfers
|
||||
|
||||
2009-08-27: v1.0.3 release
|
||||
* Bug fixes
|
||||
* Add libusb_get_max_iso_packet_size()
|
||||
|
||||
2009-06-13: v1.0.2 release
|
||||
* Bug fixes
|
||||
|
||||
2009-05-12: v1.0.1 release
|
||||
* Bug fixes
|
||||
* Darwin backend
|
||||
|
||||
2008-12-13: v1.0.0 release
|
||||
* Bug fixes
|
||||
|
||||
2008-11-21: v0.9.4 release
|
||||
* Bug fixes
|
||||
* Add libusb_attach_kernel_driver()
|
||||
|
||||
2008-08-23: v0.9.3 release
|
||||
* Bug fixes
|
||||
|
||||
2008-07-19: v0.9.2 release
|
||||
* Bug fixes
|
||||
|
||||
2008-06-28: v0.9.1 release
|
||||
* Bug fixes
|
||||
* Introduce contexts to the API
|
||||
* Compatibility with new Linux kernel features
|
||||
|
||||
2008-05-25: v0.9.0 release
|
||||
* First libusb-1.0 beta release
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
APPENDIX A - How to maintain code compatibility with versions of libusb and
|
||||
libusb that use MaxPower:
|
||||
|
||||
If you must to maintain compatibility with versions of the library that aren't
|
||||
using the bMaxPower attribute in struct libusb_config_descriptor, the
|
||||
recommended way is to use the new LIBUSB_API_VERSION macro with an #ifdef.
|
||||
For instance, if your code was written as follows:
|
||||
|
||||
if (dev->config[0].MaxPower < 250)
|
||||
|
||||
Then you should modify it to have:
|
||||
|
||||
#if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000100)
|
||||
if (dev->config[0].bMaxPower < 250)
|
||||
#else
|
||||
if (dev->config[0].MaxPower < 250)
|
||||
#endif
|
||||
25
lib/libusb/HACKING
Normal file
25
lib/libusb/HACKING
Normal file
@@ -0,0 +1,25 @@
|
||||
Contributing to libusb
|
||||
**********************
|
||||
|
||||
For larger changes or API changes/extensions it may be wise to first
|
||||
discuss on the mailing list or in the issue tracker before larger
|
||||
coding efforts are initiated.
|
||||
|
||||
If you extend or change the API make sure documentation is updated.
|
||||
Please run make -C doc and check for any Doxygen warnings.
|
||||
|
||||
Commit messages should be formatted to 72 chars width and have a
|
||||
free-standing summary line. See for instance "Commit Guidelines" on
|
||||
https://git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project
|
||||
or https://cbea.ms/git-commit/ about how to make well-formed commit
|
||||
messages.
|
||||
|
||||
Put detailed information in the commit message itself, which will end
|
||||
up in the git history. On the other hand the description that you fill
|
||||
in the GitHub pull request web page does not go anywhere.
|
||||
|
||||
For copyright reasons it is preferable to have your full name in the
|
||||
commit author field. Do not update the AUTHOR file yourself, the
|
||||
maintainers will update it as part of the release preparation.
|
||||
|
||||
Please don't touch version_nano.h in your patches or pull requests.
|
||||
52
lib/libusb/INSTALL_WIN.txt
Normal file
52
lib/libusb/INSTALL_WIN.txt
Normal file
@@ -0,0 +1,52 @@
|
||||
Installation Instructions for Windows
|
||||
*************************************
|
||||
|
||||
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:
|
||||
- Using Visual Studio 2022, open /msvc/libusb.sln
|
||||
- If you want to debug the library, uncomment the ENABLE_DEBUG_LOGGING define
|
||||
in msvc/config.h
|
||||
- Select your configuration and compile the project.
|
||||
- To target a specific toolset (previous version of Visual Studio), either
|
||||
edit PlatformToolset in /msvc/Configuration.Base.props, or supply the value
|
||||
to msbuild on the command line.
|
||||
- For example, to build for VS2015 (from a different version):
|
||||
msbuild -p:PlatformToolset=v140,Platform=x64,Configuration=Release libusb.sln
|
||||
|
||||
Installing and building libusb via vcpkg
|
||||
****************************************
|
||||
|
||||
You can download and install libusb using the vcpkg dependency manager:
|
||||
|
||||
git clone https://github.com/Microsoft/vcpkg.git
|
||||
cd vcpkg
|
||||
./bootstrap-vcpkg.bat
|
||||
./vcpkg integrate install
|
||||
vcpkg install libusb
|
||||
|
||||
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
|
||||
***********************
|
||||
|
||||
The binaries are located at:
|
||||
/build/<PlatformToolset>/<Platform>/<Configuration>/(lib|dll)/libusb-1.0.(lib|dll)
|
||||
For example: /build/v143/x64/Release/dll/libusb-1.0.dll
|
||||
|
||||
Troubleshooting
|
||||
***************
|
||||
|
||||
If the compilation process complains about missing libraries, ensure that the
|
||||
default library paths for your project points to the relevant directories.
|
||||
If needed, these libraries can be obtained by installing the latest Windows
|
||||
SDK.
|
||||
|
||||
Links
|
||||
*****
|
||||
|
||||
Additional information related to the Windows backend:
|
||||
http://windows.libusb.info
|
||||
123
lib/libusb/KEYS
Normal file
123
lib/libusb/KEYS
Normal file
@@ -0,0 +1,123 @@
|
||||
This file contains the PGP keys of libusb release managers.
|
||||
|
||||
Users:
|
||||
pgp < KEYS
|
||||
or
|
||||
gpg --import KEYS
|
||||
|
||||
Maintainers:
|
||||
pgp -kxa <your name> and append it to this file.
|
||||
or
|
||||
(pgpk -ll <your name> && pgpk -xa <your name>) >> this file.
|
||||
or
|
||||
(gpg --list-sigs <your name> && gpg --armor --export <your name>) >> this file.
|
||||
|
||||
pub rsa4096 2020-06-23 [SC]
|
||||
C68187379B23DE9EFC46651E2C80FF56C6830A0E
|
||||
uid [ultimate] Tormod Volden <debian.tormod@gmail.com>
|
||||
sub rsa4096 2020-06-23 [E]
|
||||
sub rsa4096 2020-06-23 [S]
|
||||
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQINBF7yPL0BEADQc/2dx8H7a7r1SGYph5hmkszs0O9V/43m8XhNnbnFraXjmbEv
|
||||
xm2wE6AuR301mjAqYSt/mphmH54z4GBbgmLBrK8TGdhlK0K11PeSudRN4jsLs+U3
|
||||
ErtkAHODmzyg7QiW3GWudP/lJQRSqNBoadeOdOsKMoJxm7T2a9fyyf8FR/FfShjv
|
||||
NB62jSWq0x0WnglI/V/ZOi/mOnqoggCoWXLzwqbKasicvfNsTPJIsjiu24US6mif
|
||||
nRllMWr/6aHyCOX6+x6PsQ35NF5C5B7b0c1fY7zU/UiM/JBF4HDf7jltzTIjHjho
|
||||
jTwcEkCVmunW+jSwjsLcr/zkOsu1re0W/VJJNXOhSnNUDpM7t9FeSfJ0LGlXYnGI
|
||||
5ZUCQ8w4RcKmkHYhepCjDVWYkCmxmTgO7LaAXZ5S0GeOoSDsvHNHYywAXNmB6A0s
|
||||
3kv/8i3wT8K1w9972eYW+NA6T7BfdbNk/EKxZQ74eezpRWDDPEl/zehoHQoPO3m1
|
||||
N2b06nnSKLv263IJAPdpLPUJowYdWnvmw/wyakeBMRJdI1FsDkEdI2KAvQxRKHfU
|
||||
/cTtMEJuGGR5qyze4jMHUuVqSvEsoXmSA2OLcWeZyn12jfd0CrGbCZ7jZ0R7Q1Ab
|
||||
cZ7hPsLKtgKHKyrmAdlmTgpOb2Kk2LP4ar0tuDa02YcFFAAWdRY9pORI+wARAQAB
|
||||
tCdUb3Jtb2QgVm9sZGVuIDx0b3Jtb2Qudm9sZGVuQGdtYWlsLmNvbT6JAlAEEwEI
|
||||
ADsCGwMFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AWIQTGgYc3myPenvxGZR4sgP9W
|
||||
xoMKDgUCXvI9hAIZAQAKCRAsgP9WxoMKDpcrD/i7ejrtzMGhDbB+IS5vvoK/Vk+s
|
||||
Oszn+Bi4kjq+S4wv93gByDQy5L8YHSecKS60Qi0XW3VP7qoMXaI10oo0+4pZjheM
|
||||
Lz38Xh7nOhnmzKzyPgB9sg/KuuSvcy6dZZ120ye035uckO3qDIvrV6rG9sx9EV8d
|
||||
rOKppgpXBhCC52bFp45S6bbWRLQrKlmWDNdMSQcknt86ntSqxNJDdbKoxL0JxSI8
|
||||
mB+XrM7TZvyP9eA0ZVy55cbm0ZwU2beJty72GB0Niz0ZiGWeoBcuotDkpAwou7/B
|
||||
Worgonw5yLMjL4NatZXRhym7YTNvKVovLwuG7krScghDCuGo1VswHyRi8xkkuvJ2
|
||||
YS51UBpvLsrDeLlBNd8JzL/FuBgFohkXzXjezx3gEUJe0+mc4gPdHULh8q9suRvF
|
||||
ewOuQshiqvRUacuKNYglqnxqM4aJxqO0BCNDofgnu8JYk+llXzKT5bKiIXHDMWwd
|
||||
eq9Y4NJzruAAilqM0tc1iI+qDmD4SabEjAmGREPeirVrASfrZFrOKBwF0PQE9fVN
|
||||
PsXdYCHhfXLjlEFVv5pmJkhw3euFoxDz3auZ6OhGo1ffCOZ62On5joiIRhhGQ57l
|
||||
qpW3W2Ph9TmWLRtOwR7DgiP/qUCrngBmk+Vl3KdwmSECDTXnFFKtOIHHomHEziEV
|
||||
wnjxNpVBwrvZZZkPiF0EExEIAB0WIQQsLnerYFFdSZykiO+jLYR2uvQdDAUCXvJG
|
||||
mgAKCRCjLYR2uvQdDNyVAJ9qmD3ioM5cVU3t7h4YSb6FuZ7CvQCggtBzoovIo6UJ
|
||||
WsMd6NvtKXSVsii0J1Rvcm1vZCBWb2xkZW4gPGRlYmlhbi50b3Jtb2RAZ21haWwu
|
||||
Y29tPokCTgQTAQgAOBYhBMaBhzebI96e/EZlHiyA/1bGgwoOBQJe8jy9AhsDBQsJ
|
||||
CAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJECyA/1bGgwoOFdQP/R3oBQ/fQTFoaRVK
|
||||
Q7KOp0MI2Bo1l9kRYnjj+CxlFUIEKTs06AER55IUpt1bjh4drldLVwaFP8rx/V5A
|
||||
62Z2yvIAhkrEKRFkTEbdnfH5S23VF9T8n2L4nZ6L0VBK8bgdZsiTKWk4aVy4YdQG
|
||||
yUC8mcXq1beZS8WiL7X/aH81uO+Bwaszmwgi2/NHEGdTuE1jUIslWyOHGhEe5Ygo
|
||||
+mEltm+PLdZJ9dJAEI3fWYl0Y+5y+eDNBBNXEsTiZ0R/7xFakcT2AWSnRPxbllJk
|
||||
4tG8FTlnSU8WY3VODec0L04UFJE64Ywupae0Xqc7ycJNk72FG3VEDgQhZC6e/L+a
|
||||
vSgCvzI9U8mdypxS9znyYblCGigR46M/CMzUp6oA78u3cHPUyL2fVYMm6FcQN1Bv
|
||||
nIlDSgHZJjFdpmAqYPvs+LR4+8dLXgwUKdIufka8yLJ2W3x5HQMtqBkgL8QqJTt1
|
||||
PdDbAaZdA1RHPJU2rE7sBI5EOOnQJu1cdFMOAXQR7BUad2au5IJ2oxy+z1fsZZeh
|
||||
1X8OjypTQuKrQA3oAgaAERu/qRC4c6SKG8bMMR+3tf6NVWlYS+gK2wGxXCM5DuEJ
|
||||
LYlHj2vQ/xeauq9MR23rgufVrmmnPEawMnsM5dD2ArR9FIq+sOAeZM/SJQC/I5Zf
|
||||
uM+khtkurI63QMKLxzJAJjeS/gmliF0EExEIAB0WIQQsLnerYFFdSZykiO+jLYR2
|
||||
uvQdDAUCXvJGowAKCRCjLYR2uvQdDIIVAKDcEF7MFwV/xjr7M5bTkSITiLfn/gCe
|
||||
OTXlJl/vmuXHcJl7GOPkxr5Lrbu5Ag0EXvI8vQEQAN4TW0AbNnnQ4ZeVJZWYsfBW
|
||||
dFkN42092q3herQuYRxzrEqqgwdVXplIQYKJKGdKmsBQGuqY4eXktz5EXSFPk6Ui
|
||||
YrDD6WffQoJOpZPYWB70clWSSvz+moSQSNyMOT+DhZ//CZ74YiOJTE4844HuzmkG
|
||||
lg+zS9cKKAYcz+KICKWxRaTfX/LtXKZBF3QSSy8qxCM9PipoO8bblQBGnY8rzneQ
|
||||
vAXuhsGgbtjR+o23owWHbFZKgvphsXgnmx6brJoY1o5x4qXpGrpG6XzNYp2zd3RJ
|
||||
0+8R6OIoukil/x3TGSFFp4cp2Nahb8XxV8neZ7Ng8O0+/P7sMJxPm0wuU8+DEnpB
|
||||
F6/bI1hvMNvF20dhWzpChOmArJQRZbCDM+EouZhAbh3T0n/5bx4EBezCMpDSO90V
|
||||
n0Uy3KAHbf6QohCt0PEmRSZkrGPFs3fSzuP4U8cWa07sUL02CW/pTn2i96fGgh+F
|
||||
+SfY1E56vN2Rzv7OSrbD+cNai9E4gwDGElX9ML/O3lTOok9cfSvbFxXr0ALnLCAT
|
||||
u1bI/f4Ohu9yQy4sYR+FSMNBaQmbb213PpoT5rNdn5XT/v067r8iWQlwi48a7IIM
|
||||
TNsTSGSNiBm3UoETipqQZVrgbk4gEwPsf/6BB9e2H0GSY7XBBcQb99UGQ9k88ieQ
|
||||
3jinfc2Mj8bIqCcRqwnNABEBAAGJAjYEGAEIACAWIQTGgYc3myPenvxGZR4sgP9W
|
||||
xoMKDgUCXvI8vQIbDAAKCRAsgP9WxoMKDuYcD/4rd2U6ca2/mQmNGoT2r315j2j0
|
||||
ej61a3BwoL42dX+0SgbjstIhpHo4Ng0b6MAvsA7Y6RX2P0FnBhxHQhkBUu0EbtfU
|
||||
Pewxn1WPn7qdXHLh/U3JBTWFgIvaRaqEoUVx1FAaShOex77rgwL+7NZyATSLNaW9
|
||||
J3NBY4LaKIHeqEbyHnIs9NAdnaDXxwXjTwvlz5rAbBG6r2uoUca95rWkAi/iT9D2
|
||||
cki5ouq7Lk6SGLOZAzeilKB81UsjryHmiJ1tzOWdpVTYw1Y0c30qDH/EgylmTscU
|
||||
+e4cFYo7ZqJeVXM8fNDMnU89UhOzArMgKNZEijfnUE/1qqLKNK3BRoaQrISZkYdF
|
||||
AILOfvE4yfoQxJ0joA5RJmGg1BoBsCxh6Bm25bwr9fckf2no42bG9E6a7Ib8Stkl
|
||||
MMkzdSL+6ei8wMZ/EJAGa7JYXu8wHR6fZ1bgpzbS3zejO1qReNrs+zyyT+tMHTT2
|
||||
Ax2HUpBokbPSjT6ZgWNj5XZJAPSF9S+f073D0Zr8051VU5cnI+TfGzK1OLiAcVNx
|
||||
cKM6cjSH40MUWFzHuRjlNnqrVWLcYHje8KhmfHRc6LzLR0yjz4RCfLhUnf/56Zz+
|
||||
kDGYEAOdx3mon/RG8q1yQZc0Uz3xr6+tV8jUJOaeTxvEVa6dwncBBma2BJIeVOFk
|
||||
fgu0j2XHDAKcyhnG97kCDQRe8j3JARAAs11IfLfybhdX3yjbVzxPiJ3RzkFZBbHy
|
||||
YcL8NJYdpxOGEK5pLu7zOe7z+TQpW4mMfQunbHreABunjCPuZwvME4ekQva/pky7
|
||||
S9ajdsm1HMVpoXNQ0cSD+WTkiJaDJC6LFH6+XDzrUK7Kp/6NGKCSwU5xXmZudSVd
|
||||
pCNuziE+KQ5qEXPT6P7H+1TLNKgZvxmksHA76+/ZahpVTCgVVMpTmlRa3jnH0MoN
|
||||
v5fwUMuC7fx09zdqb09D1bBcjrTltVcO6Ij8yUnw5DaQS8y8boIsIIK9YaJHk7uI
|
||||
o1qzilT7a71GKmz1Cs90qmLvRpN8nJGY6q28BXyM68E1Wx7x720IgXTR/JL/j3dB
|
||||
Yggil3GGdBLEwVPtAy8VeeiNGsJe1ZmYUYMc6rgOjghWZogjI5mJOqOXOs3Iilic
|
||||
sRTySCP4x7uRquWWlNNyeVE17ScGiUqsNCyzzwQ3MKbASswNrKnu0iIBfdYyWF+w
|
||||
iyB+kr8o23QMA7TIJnRj++ShOSeoPNg0wOns97Yj4VobSvWBmiX+VjFWkhOQFY9Q
|
||||
eFibQX3iBcSUBZh4eilQMWOx4vD9usBF9NsvrZKvIXrQI456BsTzoKFspqlka9y4
|
||||
YISw3fbGjfOSNXab2R5xEkHX8fF/u8Xs897kVIi/imRrVSgmzf3X4QdTLQJ2MdhH
|
||||
02lhlYdkvecAEQEAAYkEawQYAQgAIBYhBMaBhzebI96e/EZlHiyA/1bGgwoOBQJe
|
||||
8j3JAhsCAj8JECyA/1bGgwoOwXMgBBkBCAAdFiEEnH6pSTnGnE+8Pb+oqgY5B577
|
||||
YbkFAl7yPckACgkQqgY5B577YbkUig/3XOT/88S0edOfgNfFtntAYCj4w3NztXiR
|
||||
ClFQFohRupjP7h6y24VgKD1I0595fCGs9YKl9MiI9PAxNUVdKD6WOcjrRL6B8eMh
|
||||
xle4MefL4UK5kvUKTn2QqE8GgwAqgFkn0wbdOOxPVmGtJ3tuS5Hok9nn9RHUkeMK
|
||||
vOeRHx38NyozjZxoUJ+3gFngliM1BKlR3Dq1XlvXz/7fWKzl3AkneLHfca/0yzB6
|
||||
7qvs3G6q0btyZqjp0GSrGSVUnqpK670b1l6DQd6raej76RPq8OsxP1DkfwVsyNQV
|
||||
/EN0atj+MsruUPBbesZ5oP/XFrQkjjDDIGhbmg0xB9Bxp8v+y9EiFB9LC4nmLvw9
|
||||
gn2cK3j1JXdiKUVWzPMKdUrZ/Y5lksrn6a326zDOJZwT4/XYiclgM+vKQb1RWdXv
|
||||
bz3oTpSyeCdKZQ845aNM1Q8AHJ2NVlGBbiMsFTmKnM/wcU8+6saWflF0JeiNgal0
|
||||
wcGvmkossrOVQZh10959HT8Eb4Vzgf0MD4YATmM6CbGxv1tuDxhK12e8MDsI7wul
|
||||
M5ODLWpb3zwgLU/O3IeinbRlr30lhvnTzgdYx5CgYqUYUm/MSb0+vWpr67smoBbR
|
||||
pWi4j2zcTtay/iNL9pFCLFegkJtXwLehh8sgEj28c/jOH2XEfOgEEniVM57dFONm
|
||||
n5ba3xTKRSS8D/44K3JJSPi2urzO+wXtcbZ1QSWypTV8dI7zLImySMmBtU7GEKLe
|
||||
y8klXAQBnzyKTFrsS60A0JiNGbzw75kAi2677jgvEtzz0QAxvJUCianFT9QCqcxQ
|
||||
okh/W8klVaJGLucAD5CRTLc9F4TNGV1jsHf90McWWf/bKANz875PZUDqMDtQ6hqH
|
||||
Udn4AxVaLn1dAqn2ae3DQK043jViy7IivilQLLo5mmkGLs0bPQZgG4OBB0mgzS8Z
|
||||
t2/3zJUvS/ygea0vqMzleEMlBJXWMyh6S8upEJVGdJfuMfRbOpvRBXZULLKwBVLn
|
||||
/vcB6QianT31AtxpWRtXjk52DxrqP85jMZtrlXWECmOanNM41cN/hoVVcXYLYYrt
|
||||
f8ZYM4cjB744M3XqCjh8aw8p8sg/sMQ4yJMlLuS6tGR/4WS1EU+Rq3ukg5jFfAQ/
|
||||
PfXrj4iCFjUBD4CnRAQIXhPCqMl6hFMZw61BpKFpZNLlJ205R+elqGBbrLibhu3u
|
||||
RAeFxk23S035hxBZnC2CDQL7zLwnzk1DPx6ywS6ky2qENwISR9tNldehFuPHXnSf
|
||||
5/DxUzfWd2Tj35vxZDhKjJ1HiT3o++HKCRX9cP/cALsd5zvIxSVN6RRCUI2U8N+b
|
||||
k5/dfKNq8Q4FX9TZFSBnWudih+bT74v5f4LwhidPgOiYugiLoJh2ZqIVvQ==
|
||||
=5EaQ
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
50
lib/libusb/Makefile.am
Normal file
50
lib/libusb/Makefile.am
Normal file
@@ -0,0 +1,50 @@
|
||||
AUTOMAKE_OPTIONS = dist-bzip2 no-dist-gzip
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
EXTRA_DIST = INSTALL_WIN.txt PORTING doc/libusb.png \
|
||||
android msvc Xcode
|
||||
SUBDIRS = libusb
|
||||
|
||||
if BUILD_EXAMPLES
|
||||
SUBDIRS += examples
|
||||
endif
|
||||
|
||||
if BUILD_TESTS
|
||||
SUBDIRS += tests
|
||||
endif
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libusb-1.0.pc
|
||||
|
||||
# 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)
|
||||
sfurl = frs.sourceforge.net:/home/frs/project/libusb/libusb-1.0
|
||||
.PHONY: dist-upload
|
||||
dist-upload: dist
|
||||
rm -rf $(reldir)
|
||||
mkdir -p $(reldir)
|
||||
cp $(distdir).tar.bz2 $(reldir)
|
||||
if [ -z "$$SF_USER" ]; then \
|
||||
rsync -rv $(reldir) $(sfurl); \
|
||||
else \
|
||||
rsync -rv $(reldir) $$SF_USER@$(sfurl); \
|
||||
fi
|
||||
rm -rf $(reldir)
|
||||
2
lib/libusb/NEWS
Normal file
2
lib/libusb/NEWS
Normal file
@@ -0,0 +1,2 @@
|
||||
For the latest libusb news, please refer to the ChangeLog file, or visit:
|
||||
https://libusb.info
|
||||
94
lib/libusb/PORTING
Normal file
94
lib/libusb/PORTING
Normal file
@@ -0,0 +1,94 @@
|
||||
PORTING LIBUSB TO OTHER PLATFORMS
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
This document is aimed at developers wishing to port libusb to unsupported
|
||||
platforms. I believe the libusb API is OS-independent, so by supporting
|
||||
multiple operating systems we pave the way for cross-platform USB device
|
||||
drivers.
|
||||
|
||||
Implementation-wise, the basic idea is that you provide an interface to
|
||||
libusb's internal "backend" API, which performs the appropriate operations on
|
||||
your target platform.
|
||||
|
||||
In terms of USB I/O, your backend provides functionality to submit
|
||||
asynchronous transfers (synchronous transfers are implemented in the higher
|
||||
layers, based on the async interface). Your backend must also provide
|
||||
functionality to cancel those transfers.
|
||||
|
||||
Your backend must also provide an event handling function to "reap" ongoing
|
||||
transfers and process their results.
|
||||
|
||||
The backend must also provide standard functions for other USB operations,
|
||||
e.g. setting configuration, obtaining descriptors, etc.
|
||||
|
||||
|
||||
File descriptors for I/O polling
|
||||
================================
|
||||
|
||||
For libusb to work, your event handling function obviously needs to be called
|
||||
at various points in time. Your backend must provide a set of file descriptors
|
||||
which libusb and its users can pass to poll() or select() to determine when
|
||||
it is time to call the event handling function.
|
||||
|
||||
On Linux, this is easy: the usbfs kernel interface exposes a file descriptor
|
||||
which can be passed to poll(). If something similar is not true for your
|
||||
platform, you can emulate this using an internal library thread to reap I/O as
|
||||
necessary, and a pipe() with the main library to raise events. The file
|
||||
descriptor of the pipe can then be provided to libusb as an event source.
|
||||
|
||||
|
||||
Interface semantics and documentation
|
||||
=====================================
|
||||
|
||||
Documentation of the backend interface can be found in libusbi.h inside the
|
||||
usbi_os_backend structure definition.
|
||||
|
||||
Your implementations of these functions will need to call various internal
|
||||
libusb functions, prefixed with "usbi_". Documentation for these functions
|
||||
can be found in the .c files where they are implemented.
|
||||
|
||||
You probably want to skim over *all* the documentation before starting your
|
||||
implementation. For example, you probably need to allocate and store private
|
||||
OS-specific data for device handles, but the documentation for the mechanism
|
||||
for doing so is probably not the first thing you will see.
|
||||
|
||||
The Linux backend acts as a good example - view it as a reference
|
||||
implementation which you should try to match the behaviour of.
|
||||
|
||||
|
||||
Getting started
|
||||
===============
|
||||
|
||||
1. Modify configure.ac to detect your platform appropriately (see the OS_LINUX
|
||||
stuff for an example).
|
||||
|
||||
2. Implement your backend in the libusb/os/ directory, modifying
|
||||
libusb/os/Makefile.am appropriately.
|
||||
|
||||
3. Add preprocessor logic to the top of libusb/core.c to statically assign the
|
||||
right usbi_backend for your platform.
|
||||
|
||||
4. Produce and test your implementation.
|
||||
|
||||
5. Send your implementation to libusb-devel mailing list.
|
||||
|
||||
|
||||
Implementation difficulties? Questions?
|
||||
=======================================
|
||||
|
||||
If you encounter difficulties porting libusb to your platform, please raise
|
||||
these issues on the libusb-devel mailing list. Where possible and sensible, I
|
||||
am interested in solving problems preventing libusb from operating on other
|
||||
platforms.
|
||||
|
||||
The libusb-devel mailing list is also a good place to ask questions and
|
||||
make suggestions about the internal API. Hopefully we can produce some
|
||||
better documentation based on your questions and other input.
|
||||
|
||||
You are encouraged to get involved in the process; if the library needs
|
||||
some infrastructure additions/modifications to better support your platform,
|
||||
you are encouraged to make such changes (in cleanly distinct patch
|
||||
submissions). Even if you do not make such changes yourself, please do raise
|
||||
the issues on the mailing list at the very minimum.
|
||||
33
lib/libusb/README
Normal file
33
lib/libusb/README
Normal file
@@ -0,0 +1,33 @@
|
||||
# libusb
|
||||
|
||||
[](https://travis-ci.org/libusb/libusb)
|
||||
[](https://ci.appveyor.com/project/LudovicRousseau/libusb)
|
||||
[](https://scan.coverity.com/projects/libusb-libusb)
|
||||
|
||||
libusb is a library for USB device access from Linux, macOS,
|
||||
Windows, OpenBSD/NetBSD, Haiku, Solaris userspace, and WebAssembly
|
||||
via WebUSB.
|
||||
It is written in C (Haiku backend in C++) and licensed under the GNU
|
||||
Lesser General Public License version 2.1 or, at your option, any later
|
||||
version (see [COPYING](COPYING)).
|
||||
|
||||
libusb is abstracted internally in such a way that it can hopefully
|
||||
be ported to other operating systems. Please see the [PORTING](PORTING)
|
||||
file for more information.
|
||||
|
||||
libusb homepage:
|
||||
https://libusb.info/
|
||||
|
||||
Developers will wish to consult the API documentation:
|
||||
http://api.libusb.info
|
||||
|
||||
Use the mailing list for questions, comments, etc:
|
||||
http://mailing-list.libusb.info
|
||||
|
||||
- Hans de Goede <hdegoede@redhat.com>
|
||||
- Xiaofan Chen <xiaofanc@gmail.com>
|
||||
- Ludovic Rousseau <ludovic.rousseau@gmail.com>
|
||||
- Nathan Hjelm <hjelmn@cs.unm.edu>
|
||||
- Chris Dickens <christopher.a.dickens@gmail.com>
|
||||
|
||||
(Please use the mailing list rather than mailing developers directly)
|
||||
41
lib/libusb/README.git
Normal file
41
lib/libusb/README.git
Normal file
@@ -0,0 +1,41 @@
|
||||
Notes related to git compilation:
|
||||
--------------------------------
|
||||
|
||||
If you retrieved the libusb repository from git and are using a gcc based
|
||||
toolchain, be mindful that you should have the autotools installed (autoconf,
|
||||
automake) and will need to run either ./autogen.sh or ./bootstrap.sh to produce
|
||||
the configure file.
|
||||
|
||||
The difference between autogen.sh and bootstrap.sh is that the former invokes
|
||||
configure with a default set of options, and will therefore generate a Makefile,
|
||||
whereas the latter does not invoke configure at all. If using autogen.sh, note
|
||||
that you can also append options, that will be passed as is to configure.
|
||||
|
||||
macOS-specific notes:
|
||||
-------------------
|
||||
|
||||
Starting with Xcode 4.3, neither Xcode.app nor the Xcode 'command line tools'
|
||||
includes autotools and so running either autogen.sh or bootstrap.sh will result
|
||||
in the message:
|
||||
|
||||
libtoolize or glibtoolize was not found! Please install libtool.
|
||||
|
||||
To proceed, you must find and install it from somewhere.
|
||||
|
||||
Alternatively, you can use the Xcode project at Xcode/libusb.xcodeproj.
|
||||
|
||||
Notes related to submitting new developments:
|
||||
--------------------------------------------
|
||||
|
||||
If you submit a new development to libusb (eg: new backend), that is unlikely
|
||||
to fit in a couple of small patches, we would kindly suggest that you create a
|
||||
public account on github, if you don't have one already, and then fork a new
|
||||
libusb repository under this account from https://github.com/libusb/libusb.
|
||||
|
||||
Then you can create a git branch for your work, that we will be able to better
|
||||
reference and test.
|
||||
|
||||
We also suggest that, if you are planning to bring in a large development, you
|
||||
try to involve the libusb community early by letting the mailing list know, as
|
||||
you may find that other people might be eager to help you out.
|
||||
See http://mailing-list.libusb.info for details on how to join the mailing list.
|
||||
1
lib/libusb/README.md
Symbolic link
1
lib/libusb/README.md
Symbolic link
@@ -0,0 +1 @@
|
||||
README
|
||||
2
lib/libusb/TODO
Normal file
2
lib/libusb/TODO
Normal file
@@ -0,0 +1,2 @@
|
||||
Please see the libusb roadmap by visiting:
|
||||
https://github.com/libusb/libusb/milestones?direction=asc&sort=due_date&state=open
|
||||
92
lib/libusb/Xcode/common.xcconfig
Normal file
92
lib/libusb/Xcode/common.xcconfig
Normal file
@@ -0,0 +1,92 @@
|
||||
//
|
||||
// libusb Xcode configuration file
|
||||
// Copyright © 2012 Pete Batard <pete@akeo.ie>
|
||||
// For more information, please visit: <https://libusb.info>
|
||||
//
|
||||
// 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
|
||||
|
||||
// Use GNU11 dialect.
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11
|
||||
|
||||
// Don't search user paths with <> style #includes.
|
||||
ALWAYS_SEARCH_USER_PATHS = NO
|
||||
|
||||
// Enable weak references for Objective-C
|
||||
CLANG_ENABLE_OBJC_WEAK = YES
|
||||
|
||||
// Allocate even uninitialized global variables in the data section of the object file, rather than generating them as common blocks. This has the effect that if the same variable is declared (without 'extern') in two different compilations, you will get an error when you link them.
|
||||
GCC_NO_COMMON_BLOCKS = YES
|
||||
|
||||
// Keep private symbols private. The first setting is -fvisibility=hidden, the second is -fvisibility-inlines-hidden.
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = YES
|
||||
GCC_INLINES_ARE_PRIVATE_EXTERN = YES
|
||||
|
||||
// Compiler errors.
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES
|
||||
|
||||
// Compiler warnings.
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = 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_UNUSED_FUNCTION = YES
|
||||
GCC_WARN_UNUSED_LABEL = YES
|
||||
GCC_WARN_UNUSED_PARAMETER = YES
|
||||
GCC_WARN_UNUSED_VARIABLE = YES
|
||||
CLANG_WARN_ASSIGN_ENUM = YES
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES
|
||||
CLANG_WARN_BOOL_CONVERSION = 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_COMPLETION_HANDLER_MISUSE = YES
|
||||
CLANG_WARN_IMPLICIT_FALLTHROUGH = YES
|
||||
CLANG_WARN_FRAMEWORK_INCLUDE_PRIVATE_FROM_PUBLIC = YES
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES
|
||||
CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES
|
||||
GCC_WARN_SIGN_COMPARE = YES
|
||||
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES
|
||||
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES
|
||||
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES
|
||||
CLANG_WARN_ATOMIC_IMPLICIT_SEQ_CST = YES
|
||||
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES
|
||||
CLANG_WARN_OBJC_INTERFACE_IVARS = YES
|
||||
GCC_WARN_STRICT_SELECTOR_MATCH = YES
|
||||
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES
|
||||
|
||||
// Static analyzer warnings.
|
||||
CLANG_ANALYZER_NONNULL = YES
|
||||
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES
|
||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES
|
||||
31
lib/libusb/Xcode/config.h
Normal file
31
lib/libusb/Xcode/config.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/* config.h. Manually generated for Xcode. */
|
||||
|
||||
#include <AvailabilityMacros.h>
|
||||
|
||||
/* Define to the attribute for default visibility. */
|
||||
#define DEFAULT_VISIBILITY __attribute__ ((visibility ("default")))
|
||||
|
||||
/* Define to 1 to enable message logging. */
|
||||
#define ENABLE_LOGGING 1
|
||||
|
||||
/* 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 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)))
|
||||
|
||||
/* Enable GNU extensions. */
|
||||
#define _GNU_SOURCE 1
|
||||
32
lib/libusb/Xcode/debug.xcconfig
Normal file
32
lib/libusb/Xcode/debug.xcconfig
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// libusb Xcode configuration file
|
||||
// Copyright © 2012 Pete Batard <pete@akeo.ie>
|
||||
// For more information, please visit: <https://libusb.info>
|
||||
//
|
||||
// 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 "common.xcconfig"
|
||||
|
||||
// Embed debug symbols in binary itself.
|
||||
DEBUG_INFORMATION_FORMAT = dwarf
|
||||
|
||||
// No optimizations in debug.
|
||||
GCC_OPTIMIZATION_LEVEL = 0
|
||||
|
||||
//
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) DEBUG=1
|
||||
|
||||
// No need for Universal Binaries in debug.
|
||||
ONLY_ACTIVE_ARCH = YES
|
||||
21
lib/libusb/Xcode/libusb.xcconfig
Normal file
21
lib/libusb/Xcode/libusb.xcconfig
Normal file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// libusb Xcode configuration file
|
||||
// Copyright © 2012 Pete Batard <pete@akeo.ie>
|
||||
// For more information, please visit: <https://libusb.info>
|
||||
//
|
||||
// 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
|
||||
|
||||
PRODUCT_NAME = libusb-1.0.0
|
||||
LD_DYLIB_INSTALL_NAME = @rpath/libusb-1.0.0.dylib
|
||||
1391
lib/libusb/Xcode/libusb.xcodeproj/project.pbxproj
Normal file
1391
lib/libusb/Xcode/libusb.xcodeproj/project.pbxproj
Normal file
File diff suppressed because it is too large
Load Diff
21
lib/libusb/Xcode/libusb_debug.xcconfig
Normal file
21
lib/libusb/Xcode/libusb_debug.xcconfig
Normal file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// libusb Xcode configuration file
|
||||
// Copyright © 2012 Pete Batard <pete@akeo.ie>
|
||||
// For more information, please visit: <https://libusb.info>
|
||||
//
|
||||
// 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 "debug.xcconfig"
|
||||
#include "libusb.xcconfig"
|
||||
21
lib/libusb/Xcode/libusb_release.xcconfig
Normal file
21
lib/libusb/Xcode/libusb_release.xcconfig
Normal file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// libusb Xcode configuration file
|
||||
// Copyright © 2012 Pete Batard <pete@akeo.ie>
|
||||
// For more information, please visit: <https://libusb.info>
|
||||
//
|
||||
// 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 "release.xcconfig"
|
||||
#include "libusb.xcconfig"
|
||||
30
lib/libusb/Xcode/release.xcconfig
Normal file
30
lib/libusb/Xcode/release.xcconfig
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// libusb Xcode configuration file
|
||||
// Copyright © 2012 Pete Batard <pete@akeo.ie>
|
||||
// For more information, please visit: <https://libusb.info>
|
||||
//
|
||||
// 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 "common.xcconfig"
|
||||
|
||||
// Put debug symbols in separate .dym file.
|
||||
DEBUG_INFORMATION_FORMAT = dwarf-with-dsym
|
||||
|
||||
// Optimizations in release.
|
||||
GCC_OPTIMIZATION_LEVEL = s
|
||||
LLVM_LTO = YES
|
||||
|
||||
// Define NDEBUG so asserts go away in release.
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) NDEBUG=1
|
||||
152
lib/libusb/android/README
Normal file
152
lib/libusb/android/README
Normal file
@@ -0,0 +1,152 @@
|
||||
libusb for Android
|
||||
==================
|
||||
|
||||
Building:
|
||||
---------
|
||||
|
||||
To build libusb for Android do the following:
|
||||
|
||||
1. Download the latest NDK from:
|
||||
http://developer.android.com/tools/sdk/ndk/index.html
|
||||
|
||||
2. Extract the NDK.
|
||||
|
||||
3. Open a shell and make sure there exist an NDK global variable
|
||||
set to the directory where you extracted the NDK.
|
||||
|
||||
4. Change directory to libusb's "android/jni"
|
||||
|
||||
5. Run "$NDK/ndk-build".
|
||||
|
||||
The libusb library, examples and tests can then be found in:
|
||||
"android/libs/$ARCH"
|
||||
|
||||
Where $ARCH is one of:
|
||||
armeabi
|
||||
armeabi-v7a
|
||||
mips
|
||||
mips64
|
||||
x86
|
||||
x86_64
|
||||
|
||||
Installing:
|
||||
-----------
|
||||
|
||||
If you wish to use libusb from native code in own Android application
|
||||
then you should add the following line to your Android.mk file:
|
||||
|
||||
include $(PATH_TO_LIBUSB_SRC)/android/jni/libusb.mk
|
||||
|
||||
You will then need to add the following lines to the build
|
||||
configuration for each native binary which uses libusb:
|
||||
|
||||
LOCAL_C_INCLUDES += $(LIBUSB_ROOT_ABS)
|
||||
LOCAL_SHARED_LIBRARIES += libusb1.0
|
||||
|
||||
The Android build system will then correctly include libusb in the
|
||||
application package (APK) file, provided ndk-build is invoked before
|
||||
the package is built.
|
||||
|
||||
|
||||
Runtime Permissions:
|
||||
--------------------
|
||||
|
||||
The Runtime Permissions on Android can be transferred from Java to Native
|
||||
over the following approach:
|
||||
|
||||
JAVA:
|
||||
|
||||
--> Obtain USB permissions over the android.hardware.usb.UsbManager class
|
||||
|
||||
usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
|
||||
HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
|
||||
for (UsbDevice usbDevice : deviceList.values()) {
|
||||
usbManager.requestPermission(usbDevice, mPermissionIntent);
|
||||
}
|
||||
|
||||
--> Get the native FileDescriptor of the UsbDevice and transfer it to
|
||||
Native over JNI or JNA
|
||||
|
||||
UsbDeviceConnection usbDeviceConnection = usbManager.openDevice(camDevice);
|
||||
int fileDescriptor = usbDeviceConnection.getFileDescriptor();
|
||||
|
||||
--> JNA sample method:
|
||||
|
||||
JNA.INSTANCE.set_the_native_Descriptor(fileDescriptor);
|
||||
|
||||
NATIVE:
|
||||
|
||||
--> Initialize libusb on Android
|
||||
|
||||
set_the_native_Descriptor(int fileDescriptor) {
|
||||
libusb_context *ctx;
|
||||
libusb_device_handle *devh;
|
||||
libusb_set_option(&ctx, LIBUSB_OPTION_NO_DEVICE_DISCOVERY, NULL);
|
||||
libusb_init(&ctx);
|
||||
libusb_wrap_sys_device(NULL, (intptr_t)fileDescriptor, &devh);
|
||||
}
|
||||
/* From this point you can regularly use all libusb functions as usual */
|
||||
|
||||
About LIBUSB_OPTION_NO_DEVICE_DISCOVERY:
|
||||
|
||||
The method libusb_set_option(&ctx, LIBUSB_OPTION_NO_DEVICE_DISCOVERY, NULL)
|
||||
does not affect the ctx.
|
||||
It allows initializing libusb on unrooted Android devices by skipping
|
||||
the device enumeration.
|
||||
|
||||
Rooted Devices:
|
||||
---------------
|
||||
|
||||
For rooted devices the code using libusb could be executed as root
|
||||
using the "su" command. An alternative would be to use the "su" command
|
||||
to change the permissions on the appropriate /dev/bus/usb/ files.
|
||||
|
||||
Users have reported success in using android.hardware.usb.UsbManager
|
||||
to request permission to use the UsbDevice and then opening the
|
||||
device. The difficulties in this method is that there is no guarantee
|
||||
that it will continue to work in the future Android versions, it
|
||||
requires invoking Java APIs and running code to match each
|
||||
android.hardware.usb.UsbDevice to a libusb_device.
|
||||
|
||||
For a rooted device it is possible to install libusb into the system
|
||||
image of a running device:
|
||||
|
||||
1. Enable ADB on the device.
|
||||
|
||||
2. Connect the device to a machine running ADB.
|
||||
|
||||
3. Execute the following commands on the machine
|
||||
running ADB:
|
||||
|
||||
# Make the system partition writable
|
||||
adb shell su -c "mount -o remount,rw /system"
|
||||
|
||||
# Install libusb
|
||||
adb push obj/local/armeabi/libusb1.0.so /sdcard/
|
||||
adb shell su -c "cat > /system/lib/libusb1.0.so < /sdcard/libusb1.0.so"
|
||||
adb shell rm /sdcard/libusb1.0.so
|
||||
|
||||
# Install the samples and tests
|
||||
for B in listdevs fxload xusb sam3u_benchmark hotplugtest stress
|
||||
do
|
||||
adb push "obj/local/armeabi/$B" /sdcard/
|
||||
adb shell su -c "cat > /system/bin/$B < /sdcard/$B"
|
||||
adb shell su -c "chmod 0755 /system/bin/$B"
|
||||
adb shell rm "/sdcard/$B"
|
||||
done
|
||||
|
||||
# Make the system partition read only again
|
||||
adb shell su -c "mount -o remount,ro /system"
|
||||
|
||||
# Run listdevs to
|
||||
adb shell su -c "listdevs"
|
||||
|
||||
4. If your device only has a single OTG port then ADB can generally
|
||||
be switched to using Wifi with the following commands when connected
|
||||
via USB:
|
||||
|
||||
adb shell netcfg
|
||||
# Note the wifi IP address of the phone
|
||||
adb tcpip 5555
|
||||
# Use the IP address from netcfg
|
||||
adb connect 192.168.1.123:5555
|
||||
55
lib/libusb/android/config.h
Normal file
55
lib/libusb/android/config.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Android build config for libusb
|
||||
* Copyright © 2012-2013 RealVNC Ltd. <toby.gray@realvnc.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
|
||||
*/
|
||||
|
||||
/* Define to the attribute for default visibility. */
|
||||
#define DEFAULT_VISIBILITY __attribute__ ((visibility ("default")))
|
||||
|
||||
/* 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 to 1 if you have the <asm/types.h> header file. */
|
||||
#define HAVE_ASM_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the `clock_gettime' function. */
|
||||
#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
|
||||
301
lib/libusb/android/examples/unrooted_android.c
Normal file
301
lib/libusb/android/examples/unrooted_android.c
Normal file
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* libusb example program for reading out USB descriptors on unrooted Android
|
||||
* (based on testlibusb.c)
|
||||
*
|
||||
* Copyright 2020-2021 Peter Stoiber
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Please contact the author if you need another license.
|
||||
* This Repository is provided "as is", without warranties of any kind.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This example creates a shared object which can be accessed over JNA or JNI from Java or Kotlin in Android.
|
||||
* Hint: If you are using Android Studio, set the "Debug type" to "Java Only" to receive debug messages.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Usage:
|
||||
* First, you have to connect your USB device from the Java side.
|
||||
* Use the android.hardware.usb class to find the USB device, claim the interfaces, and open the usb_device_connection
|
||||
* Obtain the native File Descriptor --> usb_device_connection.getFileDescriptor()
|
||||
* Pass the received int value to the unrooted_usb_description method of this code (over JNA)
|
||||
*/
|
||||
|
||||
/*
|
||||
* libusb can only be included in Android projects using NDK for now. (CMake is not supported at the moment)
|
||||
* Clone the libusb git repo into your Android project and include the Android.mk file in your build.gradle.
|
||||
*/
|
||||
|
||||
/*
|
||||
Example JNA Approach:
|
||||
public interface unrooted_sample extends Library {
|
||||
public static final unrooted_sample INSTANCE = Native.load("unrooted_android", unrooted_sample.class);
|
||||
public int unrooted_usb_description (int fileDescriptor);
|
||||
}
|
||||
unrooted_sample.INSTANCE.unrooted_usb_description( usbDeviceConnection.getFileDescriptor());
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
#include <string.h>
|
||||
#include "unrooted_android.h"
|
||||
#include "libusb.h"
|
||||
#include <android/log.h>
|
||||
#define LOG_TAG "LibUsb"
|
||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
|
||||
|
||||
int verbose = 0;
|
||||
|
||||
static void print_endpoint_comp(const struct libusb_ss_endpoint_companion_descriptor *ep_comp)
|
||||
{
|
||||
LOGD(" USB 3.0 Endpoint Companion:\n");
|
||||
LOGD(" bMaxBurst: %u\n", ep_comp->bMaxBurst);
|
||||
LOGD(" bmAttributes: %02xh\n", ep_comp->bmAttributes);
|
||||
LOGD(" wBytesPerInterval: %u\n", ep_comp->wBytesPerInterval);
|
||||
}
|
||||
|
||||
static void print_endpoint(const struct libusb_endpoint_descriptor *endpoint)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
LOGD(" Endpoint:\n");
|
||||
LOGD(" bEndpointAddress: %02xh\n", endpoint->bEndpointAddress);
|
||||
LOGD(" bmAttributes: %02xh\n", endpoint->bmAttributes);
|
||||
LOGD(" wMaxPacketSize: %u\n", endpoint->wMaxPacketSize);
|
||||
LOGD(" bInterval: %u\n", endpoint->bInterval);
|
||||
LOGD(" bRefresh: %u\n", endpoint->bRefresh);
|
||||
LOGD(" bSynchAddress: %u\n", endpoint->bSynchAddress);
|
||||
|
||||
for (i = 0; i < endpoint->extra_length;) {
|
||||
if (LIBUSB_DT_SS_ENDPOINT_COMPANION == endpoint->extra[i + 1]) {
|
||||
struct libusb_ss_endpoint_companion_descriptor *ep_comp;
|
||||
|
||||
ret = libusb_get_ss_endpoint_companion_descriptor(NULL, endpoint, &ep_comp);
|
||||
if (LIBUSB_SUCCESS != ret)
|
||||
continue;
|
||||
|
||||
print_endpoint_comp(ep_comp);
|
||||
|
||||
libusb_free_ss_endpoint_companion_descriptor(ep_comp);
|
||||
}
|
||||
|
||||
i += endpoint->extra[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void print_altsetting(const struct libusb_interface_descriptor *interface)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
LOGD(" Interface:\n");
|
||||
LOGD(" bInterfaceNumber: %u\n", interface->bInterfaceNumber);
|
||||
LOGD(" bAlternateSetting: %u\n", interface->bAlternateSetting);
|
||||
LOGD(" bNumEndpoints: %u\n", interface->bNumEndpoints);
|
||||
LOGD(" bInterfaceClass: %u\n", interface->bInterfaceClass);
|
||||
LOGD(" bInterfaceSubClass: %u\n", interface->bInterfaceSubClass);
|
||||
LOGD(" bInterfaceProtocol: %u\n", interface->bInterfaceProtocol);
|
||||
LOGD(" iInterface: %u\n", interface->iInterface);
|
||||
|
||||
for (i = 0; i < interface->bNumEndpoints; i++)
|
||||
print_endpoint(&interface->endpoint[i]);
|
||||
}
|
||||
|
||||
static void print_2_0_ext_cap(struct libusb_usb_2_0_extension_descriptor *usb_2_0_ext_cap)
|
||||
{
|
||||
LOGD(" USB 2.0 Extension Capabilities:\n");
|
||||
LOGD(" bDevCapabilityType: %u\n", usb_2_0_ext_cap->bDevCapabilityType);
|
||||
LOGD(" 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)
|
||||
{
|
||||
LOGD(" USB 3.0 Capabilities:\n");
|
||||
LOGD(" bDevCapabilityType: %u\n", ss_usb_cap->bDevCapabilityType);
|
||||
LOGD(" bmAttributes: %02xh\n", ss_usb_cap->bmAttributes);
|
||||
LOGD(" wSpeedSupported: %u\n", ss_usb_cap->wSpeedSupported);
|
||||
LOGD(" bFunctionalitySupport: %u\n", ss_usb_cap->bFunctionalitySupport);
|
||||
LOGD(" bU1devExitLat: %u\n", ss_usb_cap->bU1DevExitLat);
|
||||
LOGD(" bU2devExitLat: %u\n", ss_usb_cap->bU2DevExitLat);
|
||||
}
|
||||
|
||||
static void print_bos(libusb_device_handle *handle)
|
||||
{
|
||||
struct libusb_bos_descriptor *bos;
|
||||
uint8_t i;
|
||||
int ret;
|
||||
|
||||
ret = libusb_get_bos_descriptor(handle, &bos);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
LOGD(" Binary Object Store (BOS):\n");
|
||||
LOGD(" wTotalLength: %u\n", bos->wTotalLength);
|
||||
LOGD(" bNumDeviceCaps: %u\n", bos->bNumDeviceCaps);
|
||||
|
||||
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;
|
||||
|
||||
ret = libusb_get_usb_2_0_extension_descriptor(NULL, dev_cap, &usb_2_0_extension);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
print_2_0_ext_cap(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;
|
||||
|
||||
ret = libusb_get_ss_usb_device_capability_descriptor(NULL, dev_cap, &ss_dev_cap);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
print_ss_usb_cap(ss_dev_cap);
|
||||
libusb_free_ss_usb_device_capability_descriptor(ss_dev_cap);
|
||||
}
|
||||
}
|
||||
|
||||
libusb_free_bos_descriptor(bos);
|
||||
}
|
||||
|
||||
static void print_interface(const struct libusb_interface *interface)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < interface->num_altsetting; i++)
|
||||
print_altsetting(&interface->altsetting[i]);
|
||||
}
|
||||
|
||||
static void print_configuration(struct libusb_config_descriptor *config)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
LOGD(" Configuration:\n");
|
||||
LOGD(" wTotalLength: %u\n", config->wTotalLength);
|
||||
LOGD(" bNumInterfaces: %u\n", config->bNumInterfaces);
|
||||
LOGD(" bConfigurationValue: %u\n", config->bConfigurationValue);
|
||||
LOGD(" iConfiguration: %u\n", config->iConfiguration);
|
||||
LOGD(" bmAttributes: %02xh\n", config->bmAttributes);
|
||||
LOGD(" MaxPower: %u\n", config->MaxPower);
|
||||
|
||||
for (i = 0; i < config->bNumInterfaces; i++)
|
||||
print_interface(&config->interface[i]);
|
||||
}
|
||||
|
||||
static void print_device(libusb_device *dev, libusb_device_handle *handle)
|
||||
{
|
||||
struct libusb_device_descriptor desc;
|
||||
unsigned char string[256];
|
||||
const char *speed;
|
||||
int ret;
|
||||
uint8_t i;
|
||||
|
||||
switch (libusb_get_device_speed(dev)) {
|
||||
case LIBUSB_SPEED_LOW: speed = "1.5M"; break;
|
||||
case LIBUSB_SPEED_FULL: speed = "12M"; break;
|
||||
case LIBUSB_SPEED_HIGH: speed = "480M"; break;
|
||||
case LIBUSB_SPEED_SUPER: speed = "5G"; break;
|
||||
case LIBUSB_SPEED_SUPER_PLUS: speed = "10G"; break;
|
||||
case LIBUSB_SPEED_SUPER_PLUS_X2: speed = "20G"; break;
|
||||
default: speed = "Unknown";
|
||||
}
|
||||
|
||||
ret = libusb_get_device_descriptor(dev, &desc);
|
||||
if (ret < 0) {
|
||||
LOGD("failed to get device descriptor");
|
||||
return;
|
||||
}
|
||||
|
||||
LOGD("Dev (bus %u, device %u): %04X - %04X speed: %s\n",
|
||||
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) {
|
||||
ret = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, string, sizeof(string));
|
||||
if (ret > 0)
|
||||
LOGD(" Manufacturer: %s\n", (char *)string);
|
||||
}
|
||||
|
||||
if (desc.iProduct) {
|
||||
ret = libusb_get_string_descriptor_ascii(handle, desc.iProduct, string, sizeof(string));
|
||||
if (ret > 0)
|
||||
LOGD(" Product: %s\n", (char *)string);
|
||||
}
|
||||
|
||||
if (desc.iSerialNumber && verbose) {
|
||||
ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, string, sizeof(string));
|
||||
if (ret > 0)
|
||||
LOGD(" Serial Number: %s\n", (char *)string);
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
for (i = 0; i < desc.bNumConfigurations; i++) {
|
||||
struct libusb_config_descriptor *config;
|
||||
|
||||
ret = libusb_get_config_descriptor(dev, i, &config);
|
||||
if (LIBUSB_SUCCESS != ret) {
|
||||
LOGD(" Couldn't retrieve descriptors\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
print_configuration(config);
|
||||
|
||||
libusb_free_config_descriptor(config);
|
||||
}
|
||||
|
||||
if (handle && desc.bcdUSB >= 0x0201)
|
||||
print_bos(handle);
|
||||
}
|
||||
|
||||
if (handle)
|
||||
libusb_close(handle);
|
||||
}
|
||||
|
||||
|
||||
/* fileDescriptor = the native file descriptor obtained in Java and transferred to native over JNA, for example */
|
||||
int unrooted_usb_description(int fileDescriptor)
|
||||
{
|
||||
libusb_context *ctx = NULL;
|
||||
libusb_device_handle *devh = NULL;
|
||||
int r = 0;
|
||||
verbose = 1;
|
||||
r = libusb_set_option(NULL, LIBUSB_OPTION_NO_DEVICE_DISCOVERY, NULL);
|
||||
if (r != LIBUSB_SUCCESS) {
|
||||
LOGD("libusb_set_option failed: %d\n", r);
|
||||
return -1;
|
||||
}
|
||||
r = libusb_init(&ctx);
|
||||
if (r < 0) {
|
||||
LOGD("libusb_init failed: %d\n", r);
|
||||
return r;
|
||||
}
|
||||
r = libusb_wrap_sys_device(ctx, (intptr_t)fileDescriptor, &devh);
|
||||
if (r < 0) {
|
||||
LOGD("libusb_wrap_sys_device failed: %d\n", r);
|
||||
return r;
|
||||
} else if (devh == NULL) {
|
||||
LOGD("libusb_wrap_sys_device returned invalid handle\n");
|
||||
return r;
|
||||
}
|
||||
print_device(libusb_get_device(devh), devh);
|
||||
return r;
|
||||
}
|
||||
36
lib/libusb/android/examples/unrooted_android.h
Normal file
36
lib/libusb/android/examples/unrooted_android.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2021 Peter Stoiber
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Please contact the author if you need another license.
|
||||
* This Repository is provided "as is", without warranties of any kind.
|
||||
*/
|
||||
|
||||
#ifndef unrooted_android_H
|
||||
#define unrooted_android_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int unrooted_usb_description(int fileDescriptor);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
23
lib/libusb/android/jni/Android.mk
Normal file
23
lib/libusb/android/jni/Android.mk
Normal file
@@ -0,0 +1,23 @@
|
||||
# Android build config for libusb, examples and tests
|
||||
# Copyright © 2012-2013 RealVNC Ltd. <toby.gray@realvnc.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
|
||||
#
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(LOCAL_PATH)/libusb.mk
|
||||
include $(LOCAL_PATH)/examples.mk
|
||||
include $(LOCAL_PATH)/tests.mk
|
||||
40
lib/libusb/android/jni/Application.mk
Normal file
40
lib/libusb/android/jni/Application.mk
Normal file
@@ -0,0 +1,40 @@
|
||||
# Android application build config for libusb
|
||||
# Copyright © 2012-2013 RealVNC Ltd. <toby.gray@realvnc.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
|
||||
#
|
||||
|
||||
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
|
||||
# of shared object in NDK versions at least up to r9.
|
||||
#
|
||||
APP_LDFLAGS := -llog
|
||||
168
lib/libusb/android/jni/examples.mk
Normal file
168
lib/libusb/android/jni/examples.mk
Normal file
@@ -0,0 +1,168 @@
|
||||
# Android build config for libusb examples
|
||||
# Copyright © 2012-2013 RealVNC Ltd. <toby.gray@realvnc.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
|
||||
#
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
LIBUSB_ROOT_REL := ../..
|
||||
LIBUSB_ROOT_ABS := $(LOCAL_PATH)/../..
|
||||
|
||||
ifeq ($(USE_PC_NAME),1)
|
||||
LIBUSB_MODULE := usb-1.0
|
||||
else
|
||||
LIBUSB_MODULE := libusb1.0
|
||||
endif
|
||||
|
||||
# dpfp
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
$(LIBUSB_ROOT_REL)/examples/dpfp.c
|
||||
|
||||
LOCAL_C_INCLUDES += \
|
||||
$(LOCAL_PATH)/.. \
|
||||
$(LIBUSB_ROOT_ABS)
|
||||
|
||||
LOCAL_SHARED_LIBRARIES += $(LIBUSB_MODULE)
|
||||
|
||||
LOCAL_MODULE := dpfp
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
# dpfp_threaded
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
$(LIBUSB_ROOT_REL)/examples/dpfp.c
|
||||
|
||||
LOCAL_C_INCLUDES += \
|
||||
$(LOCAL_PATH)/.. \
|
||||
$(LIBUSB_ROOT_ABS)
|
||||
|
||||
LOCAL_CFLAGS := -DDPFP_THREADED -pthread
|
||||
|
||||
LOCAL_SHARED_LIBRARIES += $(LIBUSB_MODULE)
|
||||
|
||||
LOCAL_MODULE := dpfp_threaded
|
||||
|
||||
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 += $(LIBUSB_MODULE)
|
||||
|
||||
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 += $(LIBUSB_MODULE)
|
||||
|
||||
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 += $(LIBUSB_MODULE)
|
||||
|
||||
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 += $(LIBUSB_MODULE)
|
||||
|
||||
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 += $(LIBUSB_MODULE)
|
||||
|
||||
LOCAL_MODULE := xusb
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
# unrooted_android
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
$(LIBUSB_ROOT_REL)/android/examples/unrooted_android.c
|
||||
|
||||
LOCAL_C_INCLUDES += \
|
||||
$(LOCAL_PATH)/.. \
|
||||
$(LIBUSB_ROOT_ABS)
|
||||
|
||||
LOCAL_SHARED_LIBRARIES += libusb1.0
|
||||
|
||||
LOCAL_LDLIBS += -llog
|
||||
|
||||
LOCAL_MODULE := unrooted_android
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
60
lib/libusb/android/jni/libusb.mk
Normal file
60
lib/libusb/android/jni/libusb.mk
Normal file
@@ -0,0 +1,60 @@
|
||||
# Android build config for libusb
|
||||
# Copyright © 2012-2013 RealVNC Ltd. <toby.gray@realvnc.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
|
||||
#
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
LIBUSB_ROOT_REL := ../..
|
||||
LIBUSB_ROOT_ABS := $(LOCAL_PATH)/../..
|
||||
|
||||
# libusb
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
$(LIBUSB_ROOT_REL)/libusb/core.c \
|
||||
$(LIBUSB_ROOT_REL)/libusb/descriptor.c \
|
||||
$(LIBUSB_ROOT_REL)/libusb/hotplug.c \
|
||||
$(LIBUSB_ROOT_REL)/libusb/io.c \
|
||||
$(LIBUSB_ROOT_REL)/libusb/sync.c \
|
||||
$(LIBUSB_ROOT_REL)/libusb/strerror.c \
|
||||
$(LIBUSB_ROOT_REL)/libusb/os/linux_usbfs.c \
|
||||
$(LIBUSB_ROOT_REL)/libusb/os/events_posix.c \
|
||||
$(LIBUSB_ROOT_REL)/libusb/os/threads_posix.c \
|
||||
$(LIBUSB_ROOT_REL)/libusb/os/linux_netlink.c
|
||||
|
||||
LOCAL_C_INCLUDES += \
|
||||
$(LOCAL_PATH)/.. \
|
||||
$(LIBUSB_ROOT_ABS)/libusb \
|
||||
$(LIBUSB_ROOT_ABS)/libusb/os
|
||||
|
||||
LOCAL_EXPORT_C_INCLUDES := \
|
||||
$(LIBUSB_ROOT_ABS)/libusb
|
||||
|
||||
LOCAL_CFLAGS := -fvisibility=hidden -pthread
|
||||
|
||||
LOCAL_LDLIBS := -llog
|
||||
|
||||
ifeq ($(USE_PC_NAME),1)
|
||||
LOCAL_MODULE := usb-1.0
|
||||
else
|
||||
LOCAL_MODULE := libusb1.0
|
||||
$(warning Building to legacy library name libusb1.0, which differs from pkg-config.)
|
||||
$(warning Use ndk-build USE_PC_NAME=1 to change the module name to the compatible usb-1.0.)
|
||||
$(warning USE_PC_NAME=1 may be the default in the future.)
|
||||
endif
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
45
lib/libusb/android/jni/tests.mk
Normal file
45
lib/libusb/android/jni/tests.mk
Normal file
@@ -0,0 +1,45 @@
|
||||
# Android build config for libusb tests
|
||||
# Copyright © 2012-2013 RealVNC Ltd. <toby.gray@realvnc.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
|
||||
#
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
LIBUSB_ROOT_REL := ../..
|
||||
LIBUSB_ROOT_ABS := $(LOCAL_PATH)/../..
|
||||
|
||||
ifeq ($(USE_PC_NAME),1)
|
||||
LIBUSB_MODULE := usb-1.0
|
||||
else
|
||||
LIBUSB_MODULE := libusb1.0
|
||||
endif
|
||||
|
||||
# stress
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
$(LIBUSB_ROOT_REL)/tests/stress.c \
|
||||
$(LIBUSB_ROOT_REL)/tests/testlib.c
|
||||
|
||||
LOCAL_C_INCLUDES += \
|
||||
$(LOCAL_PATH)/.. \
|
||||
$(LIBUSB_ROOT_ABS)
|
||||
|
||||
LOCAL_SHARED_LIBRARIES += $(LIBUSB_MODULE)
|
||||
|
||||
LOCAL_MODULE := stress
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
108
lib/libusb/appveyor.yml
Normal file
108
lib/libusb/appveyor.yml
Normal file
@@ -0,0 +1,108 @@
|
||||
version: 1.0.{build}
|
||||
image:
|
||||
- Visual Studio 2013
|
||||
- Visual Studio 2015
|
||||
- Visual Studio 2017
|
||||
- Visual Studio 2019
|
||||
- Visual Studio 2022
|
||||
platform:
|
||||
- Win32
|
||||
- x64
|
||||
configuration:
|
||||
- Debug
|
||||
- Release
|
||||
environment:
|
||||
toolset: UNK
|
||||
clone_depth: 1
|
||||
build:
|
||||
parallel: true
|
||||
for:
|
||||
-
|
||||
matrix:
|
||||
only:
|
||||
- image: Visual Studio 2013
|
||||
environment:
|
||||
toolset: v120
|
||||
build:
|
||||
project: msvc\libusb.sln
|
||||
|
||||
-
|
||||
matrix:
|
||||
only:
|
||||
- image: Visual Studio 2015
|
||||
configuration: Debug
|
||||
environment:
|
||||
toolset: v140
|
||||
build:
|
||||
project: msvc\libusb.sln
|
||||
|
||||
-
|
||||
matrix:
|
||||
only:
|
||||
- image: Visual Studio 2015
|
||||
platform: Win32
|
||||
configuration: Release
|
||||
environment:
|
||||
toolset: v140
|
||||
install:
|
||||
- cmd: xcopy /S /I "%APPVEYOR_BUILD_FOLDER%" C:\msys64\home\appveyor\libusb
|
||||
- cmd: xcopy /S /I "%APPVEYOR_BUILD_FOLDER%" C:\cygwin\home\appveyor\libusb
|
||||
build_script:
|
||||
- cmd: msbuild "%APPVEYOR_BUILD_FOLDER%\msvc\libusb.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:\cygwin\bin\bash -l "%APPVEYOR_BUILD_FOLDER%\.private\appveyor_build.sh" cygwin
|
||||
after_build:
|
||||
- cmd: 7z a "libusb-build_%APPVEYOR_BUILD_WORKER_IMAGE%_%PLATFORM%_%CONFIGURATION%.7z" tag_* README-build.txt build\%TOOLSET%\%PLATFORM%\%CONFIGURATION%\dll build\%TOOLSET%\%PLATFORM%\%CONFIGURATION%\lib build\%TOOLSET%\%PLATFORM%\%CONFIGURATION%\*.exe C:\msys64\home\appveyor\libusb-MinGW-Win32 C:\cygwin\home\appveyor\libusb-cygwin-Win32
|
||||
|
||||
-
|
||||
matrix:
|
||||
only:
|
||||
- image: Visual Studio 2015
|
||||
platform: x64
|
||||
configuration: Release
|
||||
environment:
|
||||
toolset: v140
|
||||
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.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
|
||||
after_build:
|
||||
- cmd: 7z a "libusb-build_%APPVEYOR_BUILD_WORKER_IMAGE%_%PLATFORM%_%CONFIGURATION%.7z" tag_* README-build.txt build\%TOOLSET%\%PLATFORM%\%CONFIGURATION%\dll build\%TOOLSET%\%PLATFORM%\%CONFIGURATION%\lib build\%TOOLSET%\%PLATFORM%\%CONFIGURATION%\*.exe C:\msys64\home\appveyor\libusb-MinGW-x64 C:\cygwin64\home\appveyor\libusb-cygwin-x64
|
||||
|
||||
-
|
||||
matrix:
|
||||
only:
|
||||
- image: Visual Studio 2017
|
||||
environment:
|
||||
toolset: v141
|
||||
build:
|
||||
project: msvc\libusb.sln
|
||||
|
||||
-
|
||||
matrix:
|
||||
only:
|
||||
- image: Visual Studio 2019
|
||||
environment:
|
||||
toolset: v142
|
||||
build:
|
||||
project: msvc\libusb.sln
|
||||
|
||||
-
|
||||
matrix:
|
||||
only:
|
||||
- image: Visual Studio 2022
|
||||
environment:
|
||||
toolset: v143
|
||||
build:
|
||||
project: msvc\libusb.sln
|
||||
|
||||
after_build:
|
||||
- cmd: ECHO This was built by %APPVEYOR_BUILD_WORKER_IMAGE% from %APPVEYOR_REPO_NAME% commit %APPVEYOR_REPO_COMMIT% > README-build.txt
|
||||
- cmd: ECHO > tag_%APPVEYOR_REPO_TAG_NAME%_commit_%APPVEYOR_REPO_COMMIT%
|
||||
- cmd: 7z a "libusb-build_%APPVEYOR_BUILD_WORKER_IMAGE%_%PLATFORM%_%CONFIGURATION%.7z" tag_* README-build.txt build\%TOOLSET%\%PLATFORM%\%CONFIGURATION%\dll build\%TOOLSET%\%PLATFORM%\%CONFIGURATION%\lib build\%TOOLSET%\%PLATFORM%\%CONFIGURATION%\*.exe
|
||||
|
||||
artifacts:
|
||||
- path: "libusb-build_%APPVEYOR_BUILD_WORKER_IMAGE%_%PLATFORM%_%CONFIGURATION%.7z"
|
||||
10
lib/libusb/autogen.sh
Executable file
10
lib/libusb/autogen.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
srcdir="$(dirname "$0")"
|
||||
|
||||
"$srcdir"/bootstrap.sh
|
||||
if [ -z "$NOCONFIGURE" ]; then
|
||||
exec "$srcdir"/configure --enable-examples-build --enable-tests-build "$@"
|
||||
fi
|
||||
10
lib/libusb/bootstrap.sh
Executable file
10
lib/libusb/bootstrap.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
if [ ! -d m4 ]; then
|
||||
mkdir m4
|
||||
fi
|
||||
exec autoreconf -ivf
|
||||
450
lib/libusb/configure.ac
Normal file
450
lib/libusb/configure.ac
Normal file
@@ -0,0 +1,450 @@
|
||||
dnl These m4 macros are whitespace sensitive and break if moved around much.
|
||||
m4_define([LU_VERSION_H], m4_include([libusb/version.h]))
|
||||
m4_define([LU_DEFINE_VERSION_ATOM],
|
||||
[m4_define([$1], m4_bregexp(LU_VERSION_H,
|
||||
[^#define\s*$1\s*\([0-9]*\).*], [\1]))])
|
||||
m4_define([LU_DEFINE_VERSION_RC_ATOM],
|
||||
[m4_define([$1], m4_bregexp(LU_VERSION_H,
|
||||
[^#define\s*$1\s*"\(-rc[0-9]*\)".*], [\1]))])
|
||||
dnl The m4_bregexp() returns (only) the numbers following the #define named
|
||||
dnl in the first macro parameter. m4_define() then defines the name for use
|
||||
dnl in AC_INIT.
|
||||
|
||||
LU_DEFINE_VERSION_ATOM([LIBUSB_MAJOR])
|
||||
LU_DEFINE_VERSION_ATOM([LIBUSB_MINOR])
|
||||
LU_DEFINE_VERSION_ATOM([LIBUSB_MICRO])
|
||||
LU_DEFINE_VERSION_RC_ATOM([LIBUSB_RC])
|
||||
|
||||
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], [https://libusb.info])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_SRCDIR([libusb/core.c])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
AC_C_INLINE
|
||||
AM_INIT_AUTOMAKE
|
||||
LT_INIT
|
||||
LT_LANG([Windows Resource])
|
||||
|
||||
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=4
|
||||
lt_revision=0
|
||||
lt_age=4
|
||||
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])
|
||||
case $host in
|
||||
*-darwin*)
|
||||
AC_MSG_RESULT([Darwin/Mac OS X])
|
||||
backend=darwin
|
||||
platform=posix
|
||||
;;
|
||||
*-haiku*)
|
||||
AC_MSG_RESULT([Haiku])
|
||||
backend=haiku
|
||||
platform=posix
|
||||
;;
|
||||
wasm*-emscripten)
|
||||
AC_MSG_RESULT([Emscripten])
|
||||
backend=emscripten
|
||||
platform=posix
|
||||
;;
|
||||
wasm*-unknown-none)
|
||||
AC_MSG_ERROR([
|
||||
--host=$host_alias is not accepted as it might become ambiguous in the future.
|
||||
Please use an explicit --host=$host_cpu-emscripten instead.
|
||||
])
|
||||
;;
|
||||
*-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*)
|
||||
AC_MSG_RESULT([SunOS])
|
||||
backend=sunos
|
||||
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="-fno-omit-frame-pointer"
|
||||
EXTRA_LDFLAGS="-static-libgcc"
|
||||
;;
|
||||
*)
|
||||
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
|
||||
|
||||
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>]])
|
||||
if test "x$backend" != xemscripten; then
|
||||
# pipe2 is detected as present on Emscripten, but it isn't actually ported and always
|
||||
# returns an error. https://github.com/emscripten-core/emscripten/issues/14824
|
||||
AC_CHECK_FUNCS([pipe2])
|
||||
fi
|
||||
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])],
|
||||
[], [])
|
||||
dnl Check for new-style atomic builtins. We first check without linking to -latomic.
|
||||
AC_MSG_CHECKING(whether __atomic_load_n is supported)
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([[
|
||||
#include <stdint.h>
|
||||
int main() {
|
||||
struct {
|
||||
uint64_t *v;
|
||||
} x;
|
||||
return (int)__atomic_load_n(x.v, __ATOMIC_ACQUIRE) &
|
||||
(int)__atomic_add_fetch(x.v, (uint64_t)1, __ATOMIC_ACQ_REL);
|
||||
}]])], GCC_ATOMIC_BUILTINS_SUPPORTED=yes, GCC_ATOMIC_BUILTINS_SUPPORTED=no)
|
||||
AC_MSG_RESULT($GCC_ATOMIC_BUILTINS_SUPPORTED)
|
||||
if test "x$GCC_ATOMIC_BUILTINS_SUPPORTED" != xyes; then
|
||||
AC_SEARCH_LIBS([__atomic_fetch_add_4], [atomic])
|
||||
fi
|
||||
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
|
||||
darwin)
|
||||
AC_CHECK_FUNCS([pthread_threadid_np])
|
||||
LIBS="${LIBS} -lobjc -Wl,-framework,IOKit -Wl,-framework,CoreFoundation -Wl,-framework,Security"
|
||||
AC_CHECK_HEADERS([IOKit/usb/IOUSBHostFamilyDefinitions.h])
|
||||
;;
|
||||
haiku)
|
||||
LIBS="${LIBS} -lbe"
|
||||
;;
|
||||
linux)
|
||||
AC_SEARCH_LIBS([clock_gettime], [rt], [], [], [])
|
||||
AC_CHECK_FUNCS([pthread_setname_np])
|
||||
AC_ARG_ENABLE([udev],
|
||||
[AS_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])])
|
||||
|
||||
# We can build umockdev tests (if available)
|
||||
m4_ifdef([PKG_PROG_PKG_CONFIG],[
|
||||
PKG_PROG_PKG_CONFIG
|
||||
PKG_CHECK_MODULES([UMOCKDEV], [umockdev-1.0 >= 0.16.0], [ac_have_umockdev=yes], [ac_have_umockdev=no])
|
||||
PKG_CHECK_MODULES([UMOCKDEV_HOTPLUG], [umockdev-1.0 >= 0.17.7], [ac_umockdev_hotplug=yes], [ac_umockdev_hotplug=no])
|
||||
if test $ac_umockdev_hotplug = yes; then
|
||||
AC_DEFINE([UMOCKDEV_HOTPLUG], [1], [UMockdev hotplug code is not racy])
|
||||
fi
|
||||
], [])
|
||||
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"
|
||||
;;
|
||||
emscripten)
|
||||
# Note: LT_LDFLAGS is not enough here because we need link flags for executable.
|
||||
EM_LDFLAGS="--bind -s ASYNCIFY"
|
||||
AM_LDFLAGS="${AM_LDFLAGS} ${EM_LDFLAGS} -s ASSERTIONS -s ALLOW_MEMORY_GROWTH"
|
||||
LIBS="${LIBS} ${EM_LDFLAGS}"
|
||||
;;
|
||||
*)
|
||||
dnl no special handling required
|
||||
;;
|
||||
esac
|
||||
|
||||
dnl headers not available on all platforms but required on others
|
||||
AC_CHECK_HEADERS([sys/time.h])
|
||||
|
||||
dnl check availability of clock_gettime(), except don't bother on Darwin, because the result is not used.
|
||||
if test "x$platform" = xposix && test "x$backend" != xdarwin; then
|
||||
AC_CHECK_FUNCS([clock_gettime], [have_clock_gettime=yes], [AC_MSG_ERROR([clock_gettime() is required on this platform])])
|
||||
|
||||
if test "x$have_clock_gettime" = xyes; then
|
||||
dnl the clock_gettime() function needs certain clock IDs defined
|
||||
AC_CHECK_DECL([CLOCK_MONOTONIC], [], [AC_MSG_ERROR([C library headers missing definition for CLOCK_MONOTONIC])], [[#include <time.h>]])
|
||||
dnl use the monotonic clock for condition variable timed waits if possible
|
||||
AC_CHECK_FUNCS([pthread_condattr_setclock], [need_clock_realtime=], [need_clock_realtime=yes])
|
||||
if test "x$need_clock_realtime" = xyes; then
|
||||
AC_CHECK_DECL([CLOCK_REALTIME], [], [AC_MSG_ERROR([C library headers missing definition for CLOCK_REALTIME])], [[#include <time.h>]])
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl eventfd support
|
||||
if test "x$backend" = xlinux || test "x$backend" = xsunos; then
|
||||
AC_ARG_ENABLE([eventfd],
|
||||
[AS_HELP_STRING([--enable-eventfd], [use eventfd for signalling [default=auto]])],
|
||||
[use_eventfd=$enableval],
|
||||
[use_eventfd=auto])
|
||||
if test "x$use_eventfd" != xno; then
|
||||
AC_CHECK_HEADER([sys/eventfd.h], [eventfd_h=yes], [eventfd_h=])
|
||||
if test "x$eventfd_h" = xyes; then
|
||||
AC_CHECK_DECLS([EFD_NONBLOCK, EFD_CLOEXEC], [eventfd_h_ok=yes], [eventfd_h_ok=], [[#include <sys/eventfd.h>]])
|
||||
if test "x$eventfd_h_ok" = xyes; then
|
||||
AC_CHECK_FUNC([eventfd], [eventfd_ok=yes], [eventfd_ok=])
|
||||
if test "x$eventfd_ok" = xyes; then
|
||||
AC_DEFINE([HAVE_EVENTFD], [1], [Define to 1 if the system has eventfd functionality.])
|
||||
elif test "x$use_eventfd" = xyes; then
|
||||
AC_MSG_ERROR([eventfd() function not found; glibc 2.9+ required])
|
||||
fi
|
||||
elif test "x$use_eventfd" = xyes; then
|
||||
AC_MSG_ERROR([eventfd header not usable; glibc 2.9+ required])
|
||||
fi
|
||||
elif test "x$use_eventfd" = xyes; then
|
||||
AC_MSG_ERROR([eventfd header not available; glibc 2.9+ required])
|
||||
fi
|
||||
fi
|
||||
AC_MSG_CHECKING([whether to use eventfd for signalling])
|
||||
if test "x$use_eventfd" = xno; then
|
||||
AC_MSG_RESULT([no (disabled by user)])
|
||||
elif test "x$eventfd_h" != xyes; then
|
||||
AC_MSG_RESULT([no (header not available)])
|
||||
elif test "x$eventfd_h_ok" != xyes; then
|
||||
AC_MSG_RESULT([no (header not usable)])
|
||||
elif test "x$eventfd_ok" != xyes; then
|
||||
AC_MSG_RESULT([no (functions not available)])
|
||||
else
|
||||
AC_MSG_RESULT([yes])
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl timerfd support
|
||||
if test "x$backend" = xlinux || test "x$backend" = xsunos; then
|
||||
AC_ARG_ENABLE([timerfd],
|
||||
[AS_HELP_STRING([--enable-timerfd], [use timerfd for timing [default=auto]])],
|
||||
[use_timerfd=$enableval],
|
||||
[use_timerfd=auto])
|
||||
if test "x$use_timerfd" != xno; then
|
||||
AC_CHECK_HEADER([sys/timerfd.h], [timerfd_h=yes], [timerfd_h=])
|
||||
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
|
||||
elif test "x$use_timerfd" = xyes; then
|
||||
AC_MSG_ERROR([timerfd header not usable; glibc 2.9+ required])
|
||||
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])
|
||||
if test "x$use_timerfd" = xno; then
|
||||
AC_MSG_RESULT([no (disabled by user)])
|
||||
elif test "x$timerfd_h" != xyes; then
|
||||
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
|
||||
|
||||
dnl Message logging
|
||||
AC_ARG_ENABLE([log],
|
||||
[AS_HELP_STRING([--disable-log], [disable all logging])],
|
||||
[log_enabled=$enableval],
|
||||
[log_enabled=yes])
|
||||
if test "x$log_enabled" != xno; then
|
||||
AC_DEFINE([ENABLE_LOGGING], [1], [Define to 1 to enable message logging.])
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE([debug-log],
|
||||
[AS_HELP_STRING([--enable-debug-log], [start with debug message logging enabled [default=no]])],
|
||||
[debug_log_enabled=$enableval],
|
||||
[debug_log_enabled=no])
|
||||
if test "x$debug_log_enabled" != xno; then
|
||||
AC_DEFINE([ENABLE_DEBUG_LOGGING], [1], [Define to 1 to start with debug message logging enabled.])
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE([system-log],
|
||||
[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=no])
|
||||
if test "x$system_log_enabled" != xno; then
|
||||
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
|
||||
dnl Check if syslog is available in standard C library
|
||||
AC_CHECK_HEADER([syslog.h], [syslog_h=yes], [syslog_h=])
|
||||
if test "x$syslog_h" = xyes; then
|
||||
AC_CHECK_FUNCS([syslog])
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl Examples build
|
||||
AC_ARG_ENABLE([examples-build],
|
||||
[AS_HELP_STRING([--enable-examples-build], [build example applications [default=no]])],
|
||||
[build_examples=$enableval],
|
||||
[build_examples=no])
|
||||
|
||||
dnl Tests build
|
||||
AC_ARG_ENABLE([tests-build],
|
||||
[AS_HELP_STRING([--enable-tests-build], [build test applications [default=no]])],
|
||||
[build_tests=$enableval],
|
||||
[build_tests=no])
|
||||
|
||||
AM_CONDITIONAL([BUILD_EXAMPLES], [test "x$build_examples" != xno])
|
||||
AM_CONDITIONAL([BUILD_TESTS], [test "x$build_tests" != xno])
|
||||
AM_CONDITIONAL([BUILD_UMOCKDEV_TEST], [test "x$ac_have_umockdev" = xyes -a "x$log_enabled" != xno -a "x$debug_log_enabled" != xyes])
|
||||
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([OS_EMSCRIPTEN], [test "x$backend" = xemscripten])
|
||||
AM_CONDITIONAL([PLATFORM_POSIX], [test "x$platform" = xposix])
|
||||
AM_CONDITIONAL([PLATFORM_WINDOWS], [test "x$platform" = xwindows])
|
||||
AM_CONDITIONAL([USE_UDEV], [test "x$use_udev" = xyes])
|
||||
|
||||
dnl The -Wcast-function-type warning causes a flurry of warnings when compiling
|
||||
dnl Windows with GCC 8 or later because of dynamically loaded functions
|
||||
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
|
||||
|
||||
dnl Some linkers do not support the '--add-stdcall-alias' option so check for it here
|
||||
if test "x$backend" = xwindows; then
|
||||
saved_CFLAGS="${CFLAGS}"
|
||||
CFLAGS="-Wl,--add-stdcall-alias"
|
||||
AC_MSG_CHECKING([if linker supports --add-stdcall-alias])
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])],
|
||||
[AC_MSG_RESULT([yes])
|
||||
LT_LDFLAGS="${LT_LDFLAGS} -Wl,--add-stdcall-alias"],
|
||||
[AC_MSG_RESULT([no])])
|
||||
CFLAGS="${saved_CFLAGS}"
|
||||
fi
|
||||
|
||||
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"
|
||||
|
||||
AM_CPPFLAGS="${EXTRA_CPPFLAGS}"
|
||||
AC_SUBST(AM_CPPFLAGS)
|
||||
|
||||
AM_CFLAGS="-std=${c_dialect}11 ${EXTRA_CFLAGS} ${SHARED_CFLAGS}"
|
||||
AC_SUBST(AM_CFLAGS)
|
||||
|
||||
AM_CXXFLAGS="-std=${c_dialect}++11 ${EXTRA_CFLAGS} ${SHARED_CFLAGS} -Wmissing-declarations"
|
||||
AC_SUBST(AM_CXXFLAGS)
|
||||
|
||||
AC_SUBST(LT_LDFLAGS)
|
||||
AC_SUBST(AM_LDFLAGS)
|
||||
|
||||
AC_SUBST([EXTRA_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([Makefile])
|
||||
AC_CONFIG_FILES([libusb/Makefile])
|
||||
AC_CONFIG_FILES([examples/Makefile])
|
||||
AC_CONFIG_FILES([tests/Makefile])
|
||||
AC_CONFIG_FILES([doc/Makefile])
|
||||
AC_CONFIG_FILES([doc/doxygen.cfg])
|
||||
AC_OUTPUT
|
||||
22
lib/libusb/doc/Makefile.in
Normal file
22
lib/libusb/doc/Makefile.in
Normal file
@@ -0,0 +1,22 @@
|
||||
LIBUSB_SRC_DIR = @top_srcdir@/libusb
|
||||
EXCLUDED_FILES = 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
|
||||
2571
lib/libusb/doc/doxygen.cfg.in
Normal file
2571
lib/libusb/doc/doxygen.cfg.in
Normal file
File diff suppressed because it is too large
Load Diff
BIN
lib/libusb/doc/libusb.png
Normal file
BIN
lib/libusb/doc/libusb.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
12
lib/libusb/examples/Makefile.am
Normal file
12
lib/libusb/examples/Makefile.am
Normal file
@@ -0,0 +1,12 @@
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/libusb
|
||||
LDADD = ../libusb/libusb-1.0.la
|
||||
LIBS =
|
||||
|
||||
noinst_PROGRAMS = dpfp dpfp_threaded fxload hotplugtest listdevs sam3u_benchmark testlibusb xusb
|
||||
|
||||
dpfp_threaded_CPPFLAGS = $(AM_CPPFLAGS) -DDPFP_THREADED
|
||||
dpfp_threaded_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
|
||||
dpfp_threaded_LDADD = $(LDADD) $(THREAD_LIBS)
|
||||
dpfp_threaded_SOURCES = dpfp.c
|
||||
|
||||
fxload_SOURCES = ezusb.c ezusb.h fxload.c
|
||||
711
lib/libusb/examples/dpfp.c
Normal file
711
lib/libusb/examples/dpfp.c
Normal file
@@ -0,0 +1,711 @@
|
||||
/*
|
||||
* libusb example program to manipulate U.are.U 4000B fingerprint scanner.
|
||||
* Copyright © 2007 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright © 2016 Nathan Hjelm <hjelmn@mac.com>
|
||||
* Copyright © 2020 Chris Dickens <christopher.a.dickens@gmail.com>
|
||||
*
|
||||
* Basic image capture program only, does not consider the powerup quirks or
|
||||
* the fact that image encryption may be enabled. Not expected to work
|
||||
* flawlessly all of the time.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libusb.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
#if defined(DPFP_THREADED)
|
||||
#if defined(PLATFORM_POSIX)
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define THREAD_RETURN_VALUE NULL
|
||||
typedef sem_t * semaphore_t;
|
||||
typedef pthread_t thread_t;
|
||||
|
||||
static inline semaphore_t semaphore_create(void)
|
||||
{
|
||||
sem_t *semaphore;
|
||||
char name[50];
|
||||
|
||||
snprintf(name, sizeof(name), "/org.libusb.example.dpfp_threaded:%d", (int)getpid());
|
||||
semaphore = sem_open(name, O_CREAT | O_EXCL, 0, 0);
|
||||
if (semaphore == SEM_FAILED)
|
||||
return NULL;
|
||||
/* Remove semaphore so that it does not persist after process exits */
|
||||
(void)sem_unlink(name);
|
||||
return semaphore;
|
||||
}
|
||||
|
||||
static inline void semaphore_give(semaphore_t semaphore)
|
||||
{
|
||||
(void)sem_post(semaphore);
|
||||
}
|
||||
|
||||
static inline void semaphore_take(semaphore_t semaphore)
|
||||
{
|
||||
(void)sem_wait(semaphore);
|
||||
}
|
||||
|
||||
static inline void semaphore_destroy(semaphore_t semaphore)
|
||||
{
|
||||
(void)sem_close(semaphore);
|
||||
}
|
||||
|
||||
static inline int thread_create(thread_t *thread,
|
||||
void *(*thread_entry)(void *arg), void *arg)
|
||||
{
|
||||
return pthread_create(thread, NULL, thread_entry, arg) == 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
static inline void thread_join(thread_t thread)
|
||||
{
|
||||
(void)pthread_join(thread, NULL);
|
||||
}
|
||||
#elif defined(PLATFORM_WINDOWS)
|
||||
#define THREAD_RETURN_VALUE 0
|
||||
typedef HANDLE semaphore_t;
|
||||
typedef HANDLE thread_t;
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
typedef DWORD thread_return_t;
|
||||
#else
|
||||
#include <process.h>
|
||||
typedef unsigned thread_return_t;
|
||||
#endif
|
||||
|
||||
static inline semaphore_t semaphore_create(void)
|
||||
{
|
||||
return CreateSemaphore(NULL, 0, 1, NULL);
|
||||
}
|
||||
|
||||
static inline void semaphore_give(semaphore_t semaphore)
|
||||
{
|
||||
(void)ReleaseSemaphore(semaphore, 1, NULL);
|
||||
}
|
||||
|
||||
static inline void semaphore_take(semaphore_t semaphore)
|
||||
{
|
||||
(void)WaitForSingleObject(semaphore, INFINITE);
|
||||
}
|
||||
|
||||
static inline void semaphore_destroy(semaphore_t semaphore)
|
||||
{
|
||||
(void)CloseHandle(semaphore);
|
||||
}
|
||||
|
||||
static inline int thread_create(thread_t *thread,
|
||||
thread_return_t (__stdcall *thread_entry)(void *arg), void *arg)
|
||||
{
|
||||
#if defined(__CYGWIN__)
|
||||
*thread = CreateThread(NULL, 0, thread_entry, arg, 0, NULL);
|
||||
#else
|
||||
*thread = (HANDLE)_beginthreadex(NULL, 0, thread_entry, arg, 0, NULL);
|
||||
#endif
|
||||
return *thread != NULL ? 0 : -1;
|
||||
}
|
||||
|
||||
static inline void thread_join(thread_t thread)
|
||||
{
|
||||
(void)WaitForSingleObject(thread, INFINITE);
|
||||
(void)CloseHandle(thread);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define EP_INTR (1 | LIBUSB_ENDPOINT_IN)
|
||||
#define EP_DATA (2 | LIBUSB_ENDPOINT_IN)
|
||||
#define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN)
|
||||
#define CTRL_OUT (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT)
|
||||
#define USB_RQ 0x04
|
||||
#define INTR_LENGTH 64
|
||||
|
||||
enum {
|
||||
MODE_INIT = 0x00,
|
||||
MODE_AWAIT_FINGER_ON = 0x10,
|
||||
MODE_AWAIT_FINGER_OFF = 0x12,
|
||||
MODE_CAPTURE = 0x20,
|
||||
MODE_SHUT_UP = 0x30,
|
||||
MODE_READY = 0x80,
|
||||
};
|
||||
|
||||
static int next_state(void);
|
||||
|
||||
enum {
|
||||
STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON = 1,
|
||||
STATE_AWAIT_IRQ_FINGER_DETECTED,
|
||||
STATE_AWAIT_MODE_CHANGE_CAPTURE,
|
||||
STATE_AWAIT_IMAGE,
|
||||
STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF,
|
||||
STATE_AWAIT_IRQ_FINGER_REMOVED,
|
||||
};
|
||||
|
||||
static int state = 0;
|
||||
static libusb_device_handle *devh = NULL;
|
||||
static unsigned char imgbuf[0x1b340];
|
||||
static unsigned char irqbuf[INTR_LENGTH];
|
||||
static struct libusb_transfer *img_transfer = NULL;
|
||||
static struct libusb_transfer *irq_transfer = NULL;
|
||||
static int img_idx = 0;
|
||||
static volatile sig_atomic_t do_exit = 0;
|
||||
|
||||
#if defined(DPFP_THREADED)
|
||||
static semaphore_t exit_semaphore;
|
||||
static thread_t poll_thread;
|
||||
#endif
|
||||
|
||||
static void request_exit(sig_atomic_t code)
|
||||
{
|
||||
do_exit = code;
|
||||
#if defined(DPFP_THREADED)
|
||||
semaphore_give(exit_semaphore);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(DPFP_THREADED)
|
||||
#if defined(PLATFORM_POSIX)
|
||||
static void *poll_thread_main(void *arg)
|
||||
#elif defined(PLATFORM_WINDOWS)
|
||||
static thread_return_t __stdcall poll_thread_main(void *arg)
|
||||
#endif
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
printf("poll thread running\n");
|
||||
|
||||
while (!do_exit) {
|
||||
struct timeval tv = { 1, 0 };
|
||||
int r;
|
||||
|
||||
r = libusb_handle_events_timeout(NULL, &tv);
|
||||
if (r < 0) {
|
||||
request_exit(2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("poll thread shutting down\n");
|
||||
return THREAD_RETURN_VALUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int find_dpfp_device(void)
|
||||
{
|
||||
devh = libusb_open_device_with_vid_pid(NULL, 0x05ba, 0x000a);
|
||||
if (!devh) {
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_f0_data(void)
|
||||
{
|
||||
unsigned char data[0x10];
|
||||
size_t i;
|
||||
int r;
|
||||
|
||||
r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0xf0, 0, data,
|
||||
sizeof(data), 0);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "F0 error %d\n", r);
|
||||
return r;
|
||||
}
|
||||
if (r < (int)sizeof(data)) {
|
||||
fprintf(stderr, "short read (%d)\n", r);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("F0 data:");
|
||||
for (i = 0; i < sizeof(data); i++)
|
||||
printf(" %02x", data[i]);
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_hwstat(unsigned char *status)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0x07, 0, status, 1, 0);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "read hwstat error %d\n", r);
|
||||
return r;
|
||||
}
|
||||
if (r < 1) {
|
||||
fprintf(stderr, "short read (%d)\n", r);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("hwstat reads %02x\n", *status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_hwstat(unsigned char data)
|
||||
{
|
||||
int r;
|
||||
|
||||
printf("set hwstat to %02x\n", data);
|
||||
r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x07, 0, &data, 1, 0);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "set hwstat error %d\n", r);
|
||||
return r;
|
||||
}
|
||||
if (r < 1) {
|
||||
fprintf(stderr, "short write (%d)\n", r);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_mode(unsigned char data)
|
||||
{
|
||||
int r;
|
||||
|
||||
printf("set mode %02x\n", data);
|
||||
r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x4e, 0, &data, 1, 0);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "set mode error %d\n", r);
|
||||
return r;
|
||||
}
|
||||
if (r < 1) {
|
||||
fprintf(stderr, "short write (%d)\n", r);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void LIBUSB_CALL cb_mode_changed(struct libusb_transfer *transfer)
|
||||
{
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
fprintf(stderr, "mode change transfer not completed!\n");
|
||||
request_exit(2);
|
||||
}
|
||||
|
||||
printf("async cb_mode_changed length=%d actual_length=%d\n",
|
||||
transfer->length, transfer->actual_length);
|
||||
if (next_state() < 0)
|
||||
request_exit(2);
|
||||
}
|
||||
|
||||
static int set_mode_async(unsigned char data)
|
||||
{
|
||||
unsigned char *buf = malloc(LIBUSB_CONTROL_SETUP_SIZE + 1);
|
||||
struct libusb_transfer *transfer;
|
||||
|
||||
if (!buf) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
transfer = libusb_alloc_transfer(0);
|
||||
if (!transfer) {
|
||||
free(buf);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("async set mode %02x\n", data);
|
||||
libusb_fill_control_setup(buf, CTRL_OUT, USB_RQ, 0x4e, 0, 1);
|
||||
buf[LIBUSB_CONTROL_SETUP_SIZE] = data;
|
||||
libusb_fill_control_transfer(transfer, devh, buf, cb_mode_changed, NULL,
|
||||
1000);
|
||||
|
||||
transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK
|
||||
| LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER;
|
||||
return libusb_submit_transfer(transfer);
|
||||
}
|
||||
|
||||
static int do_sync_intr(unsigned char *data)
|
||||
{
|
||||
int r;
|
||||
int transferred;
|
||||
|
||||
r = libusb_interrupt_transfer(devh, EP_INTR, data, INTR_LENGTH,
|
||||
&transferred, 1000);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "intr error %d\n", r);
|
||||
return r;
|
||||
}
|
||||
if (transferred < INTR_LENGTH) {
|
||||
fprintf(stderr, "short read (%d)\n", r);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("recv interrupt %04x\n", *((uint16_t *)data));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sync_intr(unsigned char type)
|
||||
{
|
||||
int r;
|
||||
unsigned char data[INTR_LENGTH];
|
||||
|
||||
while (1) {
|
||||
r = do_sync_intr(data);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (data[0] == type)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int save_to_file(unsigned char *data)
|
||||
{
|
||||
FILE *f;
|
||||
char filename[64];
|
||||
|
||||
snprintf(filename, sizeof(filename), "finger%d.pgm", img_idx++);
|
||||
f = fopen(filename, "w");
|
||||
if (!f)
|
||||
return -1;
|
||||
|
||||
fputs("P5 384 289 255 ", f);
|
||||
(void)fwrite(data + 64, 1, 384L*289L, f);
|
||||
fclose(f);
|
||||
printf("saved image to %s\n", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int next_state(void)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
printf("old state: %d\n", state);
|
||||
switch (state) {
|
||||
case STATE_AWAIT_IRQ_FINGER_REMOVED:
|
||||
state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON;
|
||||
r = set_mode_async(MODE_AWAIT_FINGER_ON);
|
||||
break;
|
||||
case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON:
|
||||
state = STATE_AWAIT_IRQ_FINGER_DETECTED;
|
||||
break;
|
||||
case STATE_AWAIT_IRQ_FINGER_DETECTED:
|
||||
state = STATE_AWAIT_MODE_CHANGE_CAPTURE;
|
||||
r = set_mode_async(MODE_CAPTURE);
|
||||
break;
|
||||
case STATE_AWAIT_MODE_CHANGE_CAPTURE:
|
||||
state = STATE_AWAIT_IMAGE;
|
||||
break;
|
||||
case STATE_AWAIT_IMAGE:
|
||||
state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF;
|
||||
r = set_mode_async(MODE_AWAIT_FINGER_OFF);
|
||||
break;
|
||||
case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF:
|
||||
state = STATE_AWAIT_IRQ_FINGER_REMOVED;
|
||||
break;
|
||||
default:
|
||||
printf("unrecognised state %d\n", state);
|
||||
}
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "error detected changing state\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
printf("new state: %d\n", state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void LIBUSB_CALL cb_irq(struct libusb_transfer *transfer)
|
||||
{
|
||||
unsigned char irqtype = transfer->buffer[0];
|
||||
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
fprintf(stderr, "irq transfer status %d?\n", transfer->status);
|
||||
goto err_free_transfer;
|
||||
}
|
||||
|
||||
printf("IRQ callback %02x\n", irqtype);
|
||||
switch (state) {
|
||||
case STATE_AWAIT_IRQ_FINGER_DETECTED:
|
||||
if (irqtype == 0x01) {
|
||||
if (next_state() < 0)
|
||||
goto err_free_transfer;
|
||||
} else {
|
||||
printf("finger-on-sensor detected in wrong state!\n");
|
||||
}
|
||||
break;
|
||||
case STATE_AWAIT_IRQ_FINGER_REMOVED:
|
||||
if (irqtype == 0x02) {
|
||||
if (next_state() < 0)
|
||||
goto err_free_transfer;
|
||||
} else {
|
||||
printf("finger-on-sensor detected in wrong state!\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (libusb_submit_transfer(irq_transfer) < 0)
|
||||
goto err_free_transfer;
|
||||
|
||||
return;
|
||||
|
||||
err_free_transfer:
|
||||
libusb_free_transfer(transfer);
|
||||
irq_transfer = NULL;
|
||||
request_exit(2);
|
||||
}
|
||||
|
||||
static void LIBUSB_CALL cb_img(struct libusb_transfer *transfer)
|
||||
{
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
fprintf(stderr, "img transfer status %d?\n", transfer->status);
|
||||
goto err_free_transfer;
|
||||
}
|
||||
|
||||
printf("Image callback\n");
|
||||
save_to_file(imgbuf);
|
||||
if (next_state() < 0)
|
||||
goto err_free_transfer;
|
||||
|
||||
if (libusb_submit_transfer(img_transfer) < 0)
|
||||
goto err_free_transfer;
|
||||
|
||||
return;
|
||||
|
||||
err_free_transfer:
|
||||
libusb_free_transfer(transfer);
|
||||
img_transfer = NULL;
|
||||
request_exit(2);
|
||||
}
|
||||
|
||||
static int init_capture(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = libusb_submit_transfer(irq_transfer);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = libusb_submit_transfer(img_transfer);
|
||||
if (r < 0) {
|
||||
libusb_cancel_transfer(irq_transfer);
|
||||
while (irq_transfer)
|
||||
if (libusb_handle_events(NULL) < 0)
|
||||
break;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* start state machine */
|
||||
state = STATE_AWAIT_IRQ_FINGER_REMOVED;
|
||||
return next_state();
|
||||
}
|
||||
|
||||
static int do_init(void)
|
||||
{
|
||||
unsigned char status;
|
||||
int r;
|
||||
|
||||
r = get_hwstat(&status);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!(status & 0x80)) {
|
||||
r = set_hwstat(status | 0x80);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = get_hwstat(&status);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
status &= ~0x80;
|
||||
r = set_hwstat(status);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = get_hwstat(&status);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sync_intr(0x56);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int alloc_transfers(void)
|
||||
{
|
||||
img_transfer = libusb_alloc_transfer(0);
|
||||
if (!img_transfer) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
irq_transfer = libusb_alloc_transfer(0);
|
||||
if (!irq_transfer) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
libusb_fill_bulk_transfer(img_transfer, devh, EP_DATA, imgbuf,
|
||||
sizeof(imgbuf), cb_img, NULL, 0);
|
||||
libusb_fill_interrupt_transfer(irq_transfer, devh, EP_INTR, irqbuf,
|
||||
sizeof(irqbuf), cb_irq, NULL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sighandler(int signum)
|
||||
{
|
||||
(void)signum;
|
||||
|
||||
request_exit(1);
|
||||
}
|
||||
|
||||
static void setup_signals(void)
|
||||
{
|
||||
#if defined(PLATFORM_POSIX)
|
||||
struct sigaction sigact;
|
||||
|
||||
sigact.sa_handler = sighandler;
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = 0;
|
||||
(void)sigaction(SIGINT, &sigact, NULL);
|
||||
(void)sigaction(SIGTERM, &sigact, NULL);
|
||||
(void)sigaction(SIGQUIT, &sigact, NULL);
|
||||
#else
|
||||
(void)signal(SIGINT, sighandler);
|
||||
(void)signal(SIGTERM, sighandler);
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = libusb_init_context(/*ctx=*/NULL, /*options=*/NULL, /*num_options=*/0);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "failed to initialise libusb %d - %s\n", r, libusb_strerror(r));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
r = find_dpfp_device();
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "Could not find/open device\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = libusb_claim_interface(devh, 0);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "claim interface error %d - %s\n", r, libusb_strerror(r));
|
||||
goto out;
|
||||
}
|
||||
printf("claimed interface\n");
|
||||
|
||||
r = print_f0_data();
|
||||
if (r < 0)
|
||||
goto out_release;
|
||||
|
||||
r = do_init();
|
||||
if (r < 0)
|
||||
goto out_deinit;
|
||||
|
||||
/* async from here onwards */
|
||||
setup_signals();
|
||||
|
||||
r = alloc_transfers();
|
||||
if (r < 0)
|
||||
goto out_deinit;
|
||||
|
||||
#if defined(DPFP_THREADED)
|
||||
exit_semaphore = semaphore_create();
|
||||
if (!exit_semaphore) {
|
||||
fprintf(stderr, "failed to initialise semaphore\n");
|
||||
goto out_deinit;
|
||||
}
|
||||
|
||||
r = thread_create(&poll_thread, poll_thread_main, NULL);
|
||||
if (r) {
|
||||
semaphore_destroy(exit_semaphore);
|
||||
goto out_deinit;
|
||||
}
|
||||
|
||||
r = init_capture();
|
||||
if (r < 0)
|
||||
request_exit(2);
|
||||
|
||||
while (!do_exit)
|
||||
semaphore_take(exit_semaphore);
|
||||
#else
|
||||
r = init_capture();
|
||||
if (r < 0)
|
||||
goto out_deinit;
|
||||
|
||||
while (!do_exit) {
|
||||
r = libusb_handle_events(NULL);
|
||||
if (r < 0)
|
||||
request_exit(2);
|
||||
}
|
||||
#endif
|
||||
|
||||
printf("shutting down...\n");
|
||||
|
||||
#if defined(DPFP_THREADED)
|
||||
thread_join(poll_thread);
|
||||
semaphore_destroy(exit_semaphore);
|
||||
#endif
|
||||
|
||||
if (img_transfer) {
|
||||
r = libusb_cancel_transfer(img_transfer);
|
||||
if (r < 0)
|
||||
fprintf(stderr, "failed to cancel transfer %d - %s\n", r, libusb_strerror(r));
|
||||
}
|
||||
|
||||
if (irq_transfer) {
|
||||
r = libusb_cancel_transfer(irq_transfer);
|
||||
if (r < 0)
|
||||
fprintf(stderr, "failed to cancel transfer %d - %s\n", r, libusb_strerror(r));
|
||||
}
|
||||
|
||||
while (img_transfer || irq_transfer) {
|
||||
if (libusb_handle_events(NULL) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (do_exit == 1)
|
||||
r = 0;
|
||||
else
|
||||
r = 1;
|
||||
|
||||
out_deinit:
|
||||
if (img_transfer)
|
||||
libusb_free_transfer(img_transfer);
|
||||
if (irq_transfer)
|
||||
libusb_free_transfer(irq_transfer);
|
||||
set_mode(0);
|
||||
set_hwstat(0x80);
|
||||
out_release:
|
||||
libusb_release_interface(devh, 0);
|
||||
out:
|
||||
libusb_close(devh);
|
||||
libusb_exit(NULL);
|
||||
return r >= 0 ? r : -r;
|
||||
}
|
||||
846
lib/libusb/examples/ezusb.c
Normal file
846
lib/libusb/examples/ezusb.c
Normal file
@@ -0,0 +1,846 @@
|
||||
/*
|
||||
* Copyright © 2001 Stephen Williams (steve@icarus.com)
|
||||
* Copyright © 2001-2002 David Brownell (dbrownell@users.sourceforge.net)
|
||||
* Copyright © 2008 Roger Williams (rawqux@users.sourceforge.net)
|
||||
* Copyright © 2012 Pete Batard (pete@akeo.ie)
|
||||
* Copyright © 2013 Federico Manzan (f.manzan@gmail.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "libusb.h"
|
||||
#include "ezusb.h"
|
||||
|
||||
/*
|
||||
* This file contains functions for uploading firmware into Cypress
|
||||
* EZ-USB microcontrollers. These chips use control endpoint 0 and vendor
|
||||
* specific commands to support writing into the on-chip SRAM. They also
|
||||
* support writing into the CPUCS register, which is how we reset the
|
||||
* processor after loading firmware (including the reset vector).
|
||||
*
|
||||
* These Cypress devices are 8-bit 8051 based microcontrollers with
|
||||
* special support for USB I/O. They come in several packages, and
|
||||
* some can be set up with external memory when device costs allow.
|
||||
* Note that the design was originally by AnchorChips, so you may find
|
||||
* references to that vendor (which was later merged into Cypress).
|
||||
* The Cypress FX parts are largely compatible with the Anchorhip ones.
|
||||
*/
|
||||
|
||||
int verbose = 1;
|
||||
|
||||
/*
|
||||
* return true if [addr,addr+len] includes external RAM
|
||||
* for Anchorchips EZ-USB or Cypress EZ-USB FX
|
||||
*/
|
||||
static bool fx_is_external(uint32_t addr, size_t len)
|
||||
{
|
||||
/* with 8KB RAM, 0x0000-0x1b3f can be written
|
||||
* we can't tell if it's a 4KB device here
|
||||
*/
|
||||
if (addr <= 0x1b3f)
|
||||
return ((addr + len) > 0x1b40);
|
||||
|
||||
/* there may be more RAM; unclear if we can write it.
|
||||
* some bulk buffers may be unused, 0x1b3f-0x1f3f
|
||||
* firmware can set ISODISAB for 2KB at 0x2000-0x27ff
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* return true if [addr,addr+len] includes external RAM
|
||||
* for Cypress EZ-USB FX2
|
||||
*/
|
||||
static bool fx2_is_external(uint32_t addr, size_t len)
|
||||
{
|
||||
/* 1st 8KB for data/code, 0x0000-0x1fff */
|
||||
if (addr <= 0x1fff)
|
||||
return ((addr + len) > 0x2000);
|
||||
|
||||
/* and 512 for data, 0xe000-0xe1ff */
|
||||
else if (addr >= 0xe000 && addr <= 0xe1ff)
|
||||
return ((addr + len) > 0xe200);
|
||||
|
||||
/* otherwise, it's certainly external */
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* return true if [addr,addr+len] includes external RAM
|
||||
* for Cypress EZ-USB FX2LP
|
||||
*/
|
||||
static bool fx2lp_is_external(uint32_t addr, size_t len)
|
||||
{
|
||||
/* 1st 16KB for data/code, 0x0000-0x3fff */
|
||||
if (addr <= 0x3fff)
|
||||
return ((addr + len) > 0x4000);
|
||||
|
||||
/* and 512 for data, 0xe000-0xe1ff */
|
||||
else if (addr >= 0xe000 && addr <= 0xe1ff)
|
||||
return ((addr + len) > 0xe200);
|
||||
|
||||
/* otherwise, it's certainly external */
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
* These are the requests (bRequest) that the bootstrap loader is expected
|
||||
* to recognize. The codes are reserved by Cypress, and these values match
|
||||
* what EZ-USB hardware, or "Vend_Ax" firmware (2nd stage loader) uses.
|
||||
* Cypress' "a3load" is nice because it supports both FX and FX2, although
|
||||
* it doesn't have the EEPROM support (subset of "Vend_Ax").
|
||||
*/
|
||||
#define RW_INTERNAL 0xA0 /* hardware implements this one */
|
||||
#define RW_MEMORY 0xA3
|
||||
|
||||
/*
|
||||
* Issues the specified vendor-specific write request.
|
||||
*/
|
||||
static int ezusb_write(libusb_device_handle *device, const char *label,
|
||||
uint8_t opcode, uint32_t addr, const unsigned char *data, size_t len)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (verbose > 1)
|
||||
logerror("%s, addr 0x%08x len %4u (0x%04x)\n", label, addr, (unsigned)len, (unsigned)len);
|
||||
status = libusb_control_transfer(device,
|
||||
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
|
||||
opcode, addr & 0xFFFF, addr >> 16,
|
||||
(unsigned char*)data, (uint16_t)len, 1000);
|
||||
if (status != (signed)len) {
|
||||
if (status < 0)
|
||||
logerror("%s: %s\n", label, libusb_error_name(status));
|
||||
else
|
||||
logerror("%s ==> %d\n", label, status);
|
||||
}
|
||||
if (status < 0) {
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Issues the specified vendor-specific read request.
|
||||
*/
|
||||
static int ezusb_read(libusb_device_handle *device, const char *label,
|
||||
uint8_t opcode, uint32_t addr, const unsigned char *data, size_t len)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (verbose > 1)
|
||||
logerror("%s, addr 0x%08x len %4u (0x%04x)\n", label, addr, (unsigned)len, (unsigned)len);
|
||||
status = libusb_control_transfer(device,
|
||||
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
|
||||
opcode, addr & 0xFFFF, addr >> 16,
|
||||
(unsigned char*)data, (uint16_t)len, 1000);
|
||||
if (status != (signed)len) {
|
||||
if (status < 0)
|
||||
logerror("%s: %s\n", label, libusb_error_name(status));
|
||||
else
|
||||
logerror("%s ==> %d\n", label, status);
|
||||
}
|
||||
if (status < 0) {
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Modifies the CPUCS register to stop or reset the CPU.
|
||||
* Returns false on error.
|
||||
*/
|
||||
static bool ezusb_cpucs(libusb_device_handle *device, uint32_t addr, bool doRun)
|
||||
{
|
||||
int status;
|
||||
uint8_t data = doRun ? 0x00 : 0x01;
|
||||
|
||||
if (verbose)
|
||||
logerror("%s\n", data ? "stop CPU" : "reset CPU");
|
||||
status = libusb_control_transfer(device,
|
||||
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
|
||||
RW_INTERNAL, addr & 0xFFFF, addr >> 16,
|
||||
&data, 1, 1000);
|
||||
if ((status != 1) &&
|
||||
/* We may get an I/O error from libusb as the device disappears */
|
||||
((!doRun) || (status != LIBUSB_ERROR_IO)))
|
||||
{
|
||||
const char *mesg = "can't modify CPUCS";
|
||||
if (status < 0)
|
||||
logerror("%s: %s\n", mesg, libusb_error_name(status));
|
||||
else
|
||||
logerror("%s\n", mesg);
|
||||
return false;
|
||||
} else
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send an FX3 jump to address command
|
||||
* Returns false on error.
|
||||
*/
|
||||
static bool ezusb_fx3_jump(libusb_device_handle *device, uint32_t addr)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (verbose)
|
||||
logerror("transfer execution to Program Entry at 0x%08x\n", addr);
|
||||
status = libusb_control_transfer(device,
|
||||
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
|
||||
RW_INTERNAL, addr & 0xFFFF, addr >> 16,
|
||||
NULL, 0, 1000);
|
||||
/* We may get an I/O error from libusb as the device disappears */
|
||||
if ((status != 0) && (status != LIBUSB_ERROR_IO))
|
||||
{
|
||||
const char *mesg = "failed to send jump command";
|
||||
if (status < 0)
|
||||
logerror("%s: %s\n", mesg, libusb_error_name(status));
|
||||
else
|
||||
logerror("%s\n", mesg);
|
||||
return false;
|
||||
} else
|
||||
return true;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Parse an Intel HEX image file and invoke the poke() function on the
|
||||
* various segments to implement policies such as writing to RAM (with
|
||||
* a one or two stage loader setup, depending on the firmware) or to
|
||||
* EEPROM (two stages required).
|
||||
*
|
||||
* image - the hex image file
|
||||
* context - for use by poke()
|
||||
* is_external - if non-null, used to check which segments go into
|
||||
* external memory (writable only by software loader)
|
||||
* poke - called with each memory segment; errors indicated
|
||||
* by returning negative values.
|
||||
*
|
||||
* Caller is responsible for halting CPU as needed, such as when
|
||||
* overwriting a second stage loader.
|
||||
*/
|
||||
static int parse_ihex(FILE *image, void *context,
|
||||
bool (*is_external)(uint32_t addr, size_t len),
|
||||
int (*poke) (void *context, uint32_t addr, bool external,
|
||||
const unsigned char *data, size_t len))
|
||||
{
|
||||
unsigned char data[1023];
|
||||
uint32_t data_addr = 0;
|
||||
size_t data_len = 0;
|
||||
int rc;
|
||||
int first_line = 1;
|
||||
bool external = false;
|
||||
|
||||
/* Read the input file as an IHEX file, and report the memory segments
|
||||
* as we go. Each line holds a max of 16 bytes, but uploading is
|
||||
* faster (and EEPROM space smaller) if we merge those lines into larger
|
||||
* chunks. Most hex files keep memory segments together, which makes
|
||||
* such merging all but free. (But it may still be worth sorting the
|
||||
* hex files to make up for undesirable behavior from tools.)
|
||||
*
|
||||
* Note that EEPROM segments max out at 1023 bytes; the upload protocol
|
||||
* allows segments of up to 64 KBytes (more than a loader could handle).
|
||||
*/
|
||||
for (;;) {
|
||||
char buf[512], *cp;
|
||||
char tmp, type;
|
||||
size_t len;
|
||||
unsigned idx, off;
|
||||
|
||||
cp = fgets(buf, sizeof(buf), image);
|
||||
if (cp == NULL) {
|
||||
logerror("EOF without EOF record!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* EXTENSION: "# comment-till-end-of-line", for copyrights etc */
|
||||
if (buf[0] == '#')
|
||||
continue;
|
||||
|
||||
if (buf[0] != ':') {
|
||||
logerror("not an ihex record: %s", buf);
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* ignore any newline */
|
||||
cp = strchr(buf, '\n');
|
||||
if (cp)
|
||||
*cp = 0;
|
||||
|
||||
if (verbose >= 3)
|
||||
logerror("** LINE: %s\n", buf);
|
||||
|
||||
/* Read the length field (up to 16 bytes) */
|
||||
tmp = buf[3];
|
||||
buf[3] = 0;
|
||||
len = strtoul(buf+1, NULL, 16);
|
||||
buf[3] = tmp;
|
||||
|
||||
/* Read the target offset (address up to 64KB) */
|
||||
tmp = buf[7];
|
||||
buf[7] = 0;
|
||||
off = (unsigned int)strtoul(buf+3, NULL, 16);
|
||||
buf[7] = tmp;
|
||||
|
||||
/* Initialize data_addr */
|
||||
if (first_line) {
|
||||
data_addr = off;
|
||||
first_line = 0;
|
||||
}
|
||||
|
||||
/* Read the record type */
|
||||
tmp = buf[9];
|
||||
buf[9] = 0;
|
||||
type = (char)strtoul(buf+7, NULL, 16);
|
||||
buf[9] = tmp;
|
||||
|
||||
/* If this is an EOF record, then make it so. */
|
||||
if (type == 1) {
|
||||
if (verbose >= 2)
|
||||
logerror("EOF on hexfile\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (type != 0) {
|
||||
logerror("unsupported record type: %u\n", type);
|
||||
return -3;
|
||||
}
|
||||
|
||||
if ((len * 2) + 11 > strlen(buf)) {
|
||||
logerror("record too short?\n");
|
||||
return -4;
|
||||
}
|
||||
|
||||
/* FIXME check for _physically_ contiguous not just virtually
|
||||
* e.g. on FX2 0x1f00-0x2100 includes both on-chip and external
|
||||
* memory so it's not really contiguous */
|
||||
|
||||
/* flush the saved data if it's not contiguous,
|
||||
* or when we've buffered as much as we can.
|
||||
*/
|
||||
if (data_len != 0
|
||||
&& (off != (data_addr + data_len)
|
||||
/* || !merge */
|
||||
|| (data_len + len) > sizeof(data))) {
|
||||
if (is_external)
|
||||
external = is_external(data_addr, data_len);
|
||||
rc = poke(context, data_addr, external, data, data_len);
|
||||
if (rc < 0)
|
||||
return -1;
|
||||
data_addr = off;
|
||||
data_len = 0;
|
||||
}
|
||||
|
||||
/* append to saved data, flush later */
|
||||
for (idx = 0, cp = buf+9 ; idx < len ; idx += 1, cp += 2) {
|
||||
tmp = cp[2];
|
||||
cp[2] = 0;
|
||||
data[data_len + idx] = (uint8_t)strtoul(cp, NULL, 16);
|
||||
cp[2] = tmp;
|
||||
}
|
||||
data_len += len;
|
||||
}
|
||||
|
||||
|
||||
/* flush any data remaining */
|
||||
if (data_len != 0) {
|
||||
if (is_external)
|
||||
external = is_external(data_addr, data_len);
|
||||
rc = poke(context, data_addr, external, data, data_len);
|
||||
if (rc < 0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a binary image file and write it as is to the target.
|
||||
* Applies to Cypress BIX images for RAM or Cypress IIC images
|
||||
* for EEPROM.
|
||||
*
|
||||
* image - the BIX image file
|
||||
* context - for use by poke()
|
||||
* is_external - if non-null, used to check which segments go into
|
||||
* external memory (writable only by software loader)
|
||||
* poke - called with each memory segment; errors indicated
|
||||
* by returning negative values.
|
||||
*
|
||||
* Caller is responsible for halting CPU as needed, such as when
|
||||
* overwriting a second stage loader.
|
||||
*/
|
||||
static int parse_bin(FILE *image, void *context,
|
||||
bool (*is_external)(uint32_t addr, size_t len), int (*poke)(void *context,
|
||||
uint32_t addr, bool external, const unsigned char *data, size_t len))
|
||||
{
|
||||
unsigned char data[4096];
|
||||
uint32_t data_addr = 0;
|
||||
size_t data_len = 0;
|
||||
int rc;
|
||||
bool external = false;
|
||||
|
||||
for (;;) {
|
||||
data_len = fread(data, 1, 4096, image);
|
||||
if (data_len == 0)
|
||||
break;
|
||||
if (is_external)
|
||||
external = is_external(data_addr, data_len);
|
||||
rc = poke(context, data_addr, external, data, data_len);
|
||||
if (rc < 0)
|
||||
return -1;
|
||||
data_addr += (uint32_t)data_len;
|
||||
}
|
||||
return feof(image)?0:-1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a Cypress IIC image file and invoke the poke() function on the
|
||||
* various segments for writing to RAM
|
||||
*
|
||||
* image - the IIC image file
|
||||
* context - for use by poke()
|
||||
* is_external - if non-null, used to check which segments go into
|
||||
* external memory (writable only by software loader)
|
||||
* poke - called with each memory segment; errors indicated
|
||||
* by returning negative values.
|
||||
*
|
||||
* Caller is responsible for halting CPU as needed, such as when
|
||||
* overwriting a second stage loader.
|
||||
*/
|
||||
static int parse_iic(FILE *image, void *context,
|
||||
bool (*is_external)(uint32_t addr, size_t len),
|
||||
int (*poke)(void *context, uint32_t addr, bool external, const unsigned char *data, size_t len))
|
||||
{
|
||||
unsigned char data[4096];
|
||||
uint32_t data_addr = 0;
|
||||
size_t data_len = 0, read_len;
|
||||
uint8_t block_header[4];
|
||||
int rc;
|
||||
bool external = false;
|
||||
long file_size, initial_pos;
|
||||
|
||||
initial_pos = ftell(image);
|
||||
if (initial_pos < 0)
|
||||
return -1;
|
||||
|
||||
if (fseek(image, 0L, SEEK_END) != 0)
|
||||
return -1;
|
||||
file_size = ftell(image);
|
||||
if (fseek(image, initial_pos, SEEK_SET) != 0)
|
||||
return -1;
|
||||
for (;;) {
|
||||
/* Ignore the trailing reset IIC data (5 bytes) */
|
||||
if (ftell(image) >= (file_size - 5))
|
||||
break;
|
||||
if (fread(&block_header, 1, sizeof(block_header), image) != 4) {
|
||||
logerror("unable to read IIC block header\n");
|
||||
return -1;
|
||||
}
|
||||
data_len = (block_header[0] << 8) + block_header[1];
|
||||
data_addr = (block_header[2] << 8) + block_header[3];
|
||||
if (data_len > sizeof(data)) {
|
||||
/* If this is ever reported as an error, switch to using malloc/realloc */
|
||||
logerror("IIC data block too small - please report this error to libusb.info\n");
|
||||
return -1;
|
||||
}
|
||||
read_len = fread(data, 1, data_len, image);
|
||||
if (read_len != data_len) {
|
||||
logerror("read error\n");
|
||||
return -1;
|
||||
}
|
||||
if (is_external)
|
||||
external = is_external(data_addr, data_len);
|
||||
rc = poke(context, data_addr, external, data, data_len);
|
||||
if (rc < 0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* the parse call will be selected according to the image type */
|
||||
static int (*parse[IMG_TYPE_MAX])(FILE *image, void *context, bool (*is_external)(uint32_t addr, size_t len),
|
||||
int (*poke)(void *context, uint32_t addr, bool external, const unsigned char *data, size_t len))
|
||||
= { parse_ihex, parse_iic, parse_bin };
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
* For writing to RAM using a first (hardware) or second (software)
|
||||
* stage loader and 0xA0 or 0xA3 vendor requests
|
||||
*/
|
||||
typedef enum {
|
||||
_undef = 0,
|
||||
internal_only, /* hardware first-stage loader */
|
||||
skip_internal, /* first phase, second-stage loader */
|
||||
skip_external /* second phase, second-stage loader */
|
||||
} ram_mode;
|
||||
|
||||
struct ram_poke_context {
|
||||
libusb_device_handle *device;
|
||||
ram_mode mode;
|
||||
size_t total, count;
|
||||
};
|
||||
|
||||
#define RETRY_LIMIT 5
|
||||
|
||||
static int ram_poke(void *context, uint32_t addr, bool external,
|
||||
const unsigned char *data, size_t len)
|
||||
{
|
||||
struct ram_poke_context *ctx = (struct ram_poke_context*)context;
|
||||
int rc;
|
||||
unsigned retry = 0;
|
||||
|
||||
switch (ctx->mode) {
|
||||
case internal_only: /* CPU should be stopped */
|
||||
if (external) {
|
||||
logerror("can't write %u bytes external memory at 0x%08x\n",
|
||||
(unsigned)len, addr);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case skip_internal: /* CPU must be running */
|
||||
if (!external) {
|
||||
if (verbose >= 2) {
|
||||
logerror("SKIP on-chip RAM, %u bytes at 0x%08x\n",
|
||||
(unsigned)len, addr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case skip_external: /* CPU should be stopped */
|
||||
if (external) {
|
||||
if (verbose >= 2) {
|
||||
logerror("SKIP external RAM, %u bytes at 0x%08x\n",
|
||||
(unsigned)len, addr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case _undef:
|
||||
default:
|
||||
logerror("bug\n");
|
||||
errno = EDOM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->total += len;
|
||||
ctx->count++;
|
||||
|
||||
/* Retry this till we get a real error. Control messages are not
|
||||
* NAKed (just dropped) so time out means is a real problem.
|
||||
*/
|
||||
while ((rc = ezusb_write(ctx->device,
|
||||
external ? "write external" : "write on-chip",
|
||||
external ? RW_MEMORY : RW_INTERNAL,
|
||||
addr, data, len)) < 0
|
||||
&& retry < RETRY_LIMIT) {
|
||||
if (rc != LIBUSB_ERROR_TIMEOUT)
|
||||
break;
|
||||
retry += 1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load a Cypress Image file into target RAM.
|
||||
* See http://www.cypress.com/?docID=41351 (AN76405 PDF) for more info.
|
||||
*/
|
||||
static int fx3_load_ram(libusb_device_handle *device, const char *path)
|
||||
{
|
||||
uint32_t dCheckSum, dExpectedCheckSum, dAddress, i, dLen, dLength;
|
||||
uint32_t* dImageBuf;
|
||||
unsigned char *bBuf, hBuf[4], blBuf[4], rBuf[4096];
|
||||
FILE *image;
|
||||
int ret = 0;
|
||||
|
||||
image = fopen(path, "rb");
|
||||
if (image == NULL) {
|
||||
logerror("unable to open '%s' for input\n", path);
|
||||
return -2;
|
||||
} else if (verbose)
|
||||
logerror("open firmware image %s for RAM upload\n", path);
|
||||
|
||||
// Read header
|
||||
if (fread(hBuf, sizeof(char), sizeof(hBuf), image) != sizeof(hBuf)) {
|
||||
logerror("could not read image header");
|
||||
ret = -3;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// check "CY" signature byte and format
|
||||
if ((hBuf[0] != 'C') || (hBuf[1] != 'Y')) {
|
||||
logerror("image doesn't have a CYpress signature\n");
|
||||
ret = -3;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// Check bImageType
|
||||
switch(hBuf[3]) {
|
||||
case 0xB0:
|
||||
if (verbose)
|
||||
logerror("normal FW binary %s image with checksum\n", (hBuf[2]&0x01)?"data":"executable");
|
||||
break;
|
||||
case 0xB1:
|
||||
logerror("security binary image is not currently supported\n");
|
||||
ret = -3;
|
||||
goto exit;
|
||||
case 0xB2:
|
||||
logerror("VID:PID image is not currently supported\n");
|
||||
ret = -3;
|
||||
goto exit;
|
||||
default:
|
||||
logerror("invalid image type 0x%02X\n", hBuf[3]);
|
||||
ret = -3;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// Read the bootloader version
|
||||
if (verbose) {
|
||||
if ((ezusb_read(device, "read bootloader version", RW_INTERNAL, 0xFFFF0020, blBuf, 4) < 0)) {
|
||||
logerror("Could not read bootloader version\n");
|
||||
ret = -8;
|
||||
goto exit;
|
||||
}
|
||||
logerror("FX3 bootloader version: 0x%02X%02X%02X%02X\n", blBuf[3], blBuf[2], blBuf[1], blBuf[0]);
|
||||
}
|
||||
|
||||
dCheckSum = 0;
|
||||
if (verbose)
|
||||
logerror("writing image...\n");
|
||||
while (1) {
|
||||
if ((fread(&dLength, sizeof(uint32_t), 1, image) != 1) || // read dLength
|
||||
(fread(&dAddress, sizeof(uint32_t), 1, image) != 1)) { // read dAddress
|
||||
logerror("could not read image");
|
||||
ret = -3;
|
||||
goto exit;
|
||||
}
|
||||
if (dLength == 0)
|
||||
break; // done
|
||||
|
||||
// coverity[tainted_data]
|
||||
dImageBuf = (uint32_t*)calloc(dLength, sizeof(uint32_t));
|
||||
if (dImageBuf == NULL) {
|
||||
logerror("could not allocate buffer for image chunk\n");
|
||||
ret = -4;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// read sections
|
||||
if (fread(dImageBuf, sizeof(uint32_t), dLength, image) != dLength) {
|
||||
logerror("could not read image");
|
||||
free(dImageBuf);
|
||||
ret = -3;
|
||||
goto exit;
|
||||
}
|
||||
for (i = 0; i < dLength; i++)
|
||||
dCheckSum += dImageBuf[i];
|
||||
dLength <<= 2; // convert to Byte length
|
||||
bBuf = (unsigned char*) dImageBuf;
|
||||
|
||||
while (dLength > 0) {
|
||||
dLen = 4096; // 4K max
|
||||
if (dLen > dLength)
|
||||
dLen = dLength;
|
||||
if ((ezusb_write(device, "write firmware", RW_INTERNAL, dAddress, bBuf, dLen) < 0) ||
|
||||
(ezusb_read(device, "read firmware", RW_INTERNAL, dAddress, rBuf, dLen) < 0)) {
|
||||
logerror("R/W error\n");
|
||||
free(dImageBuf);
|
||||
ret = -5;
|
||||
goto exit;
|
||||
}
|
||||
// Verify data: rBuf with bBuf
|
||||
for (i = 0; i < dLen; i++) {
|
||||
if (rBuf[i] != bBuf[i]) {
|
||||
logerror("verify error");
|
||||
free(dImageBuf);
|
||||
ret = -6;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
dLength -= dLen;
|
||||
bBuf += dLen;
|
||||
dAddress += dLen;
|
||||
}
|
||||
free(dImageBuf);
|
||||
}
|
||||
|
||||
// read pre-computed checksum data
|
||||
if ((fread(&dExpectedCheckSum, sizeof(uint32_t), 1, image) != 1) ||
|
||||
(dCheckSum != dExpectedCheckSum)) {
|
||||
logerror("checksum error\n");
|
||||
ret = -7;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// transfer execution to Program Entry
|
||||
if (!ezusb_fx3_jump(device, dAddress)) {
|
||||
ret = -6;
|
||||
}
|
||||
|
||||
exit:
|
||||
fclose(image);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load a firmware file into target RAM. device is the open libusb
|
||||
* device, and the path is the name of the source file. Open the file,
|
||||
* parse the bytes, and write them in one or two phases.
|
||||
*
|
||||
* If stage == 0, this uses the first stage loader, built into EZ-USB
|
||||
* hardware but limited to writing on-chip memory or CPUCS. Everything
|
||||
* is written during one stage, unless there's an error such as the image
|
||||
* holding data that needs to be written to external memory.
|
||||
*
|
||||
* Otherwise, things are written in two stages. First the external
|
||||
* memory is written, expecting a second stage loader to have already
|
||||
* been loaded. Then file is re-parsed and on-chip memory is written.
|
||||
*/
|
||||
int ezusb_load_ram(libusb_device_handle *device, const char *path, int fx_type, int img_type, int stage)
|
||||
{
|
||||
FILE *image;
|
||||
uint32_t cpucs_addr;
|
||||
bool (*is_external)(uint32_t off, size_t len);
|
||||
struct ram_poke_context ctx;
|
||||
int status;
|
||||
uint8_t iic_header[8] = { 0 };
|
||||
int ret = 0;
|
||||
|
||||
if (fx_type == FX_TYPE_FX3)
|
||||
return fx3_load_ram(device, path);
|
||||
|
||||
image = fopen(path, "rb");
|
||||
if (image == NULL) {
|
||||
logerror("%s: unable to open for input.\n", path);
|
||||
return -2;
|
||||
} else if (verbose > 1)
|
||||
logerror("open firmware image %s for RAM upload\n", path);
|
||||
|
||||
if (img_type == IMG_TYPE_IIC) {
|
||||
if ( (fread(iic_header, 1, sizeof(iic_header), image) != sizeof(iic_header))
|
||||
|| (((fx_type == FX_TYPE_FX2LP) || (fx_type == FX_TYPE_FX2)) && (iic_header[0] != 0xC2))
|
||||
|| ((fx_type == FX_TYPE_AN21) && (iic_header[0] != 0xB2))
|
||||
|| ((fx_type == FX_TYPE_FX1) && (iic_header[0] != 0xB6)) ) {
|
||||
logerror("IIC image does not contain executable code - cannot load to RAM.\n");
|
||||
ret = -1;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* EZ-USB original/FX and FX2 devices differ, apart from the 8051 core */
|
||||
switch(fx_type) {
|
||||
case FX_TYPE_FX2LP:
|
||||
cpucs_addr = 0xe600;
|
||||
is_external = fx2lp_is_external;
|
||||
break;
|
||||
case FX_TYPE_FX2:
|
||||
cpucs_addr = 0xe600;
|
||||
is_external = fx2_is_external;
|
||||
break;
|
||||
default:
|
||||
cpucs_addr = 0x7f92;
|
||||
is_external = fx_is_external;
|
||||
break;
|
||||
}
|
||||
|
||||
/* use only first stage loader? */
|
||||
if (stage == 0) {
|
||||
ctx.mode = internal_only;
|
||||
|
||||
/* if required, halt the CPU while we overwrite its code/data */
|
||||
if (cpucs_addr && !ezusb_cpucs(device, cpucs_addr, false))
|
||||
{
|
||||
ret = -1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* 2nd stage, first part? loader was already uploaded */
|
||||
} else {
|
||||
ctx.mode = skip_internal;
|
||||
|
||||
/* let CPU run; overwrite the 2nd stage loader later */
|
||||
if (verbose)
|
||||
logerror("2nd stage: write external memory\n");
|
||||
}
|
||||
|
||||
/* scan the image, first (maybe only) time */
|
||||
ctx.device = device;
|
||||
ctx.total = ctx.count = 0;
|
||||
status = parse[img_type](image, &ctx, is_external, ram_poke);
|
||||
if (status < 0) {
|
||||
logerror("unable to upload %s\n", path);
|
||||
ret = status;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* second part of 2nd stage: rescan */
|
||||
// TODO: what should we do for non HEX images there?
|
||||
if (stage) {
|
||||
ctx.mode = skip_external;
|
||||
|
||||
/* if needed, halt the CPU while we overwrite the 1st stage loader */
|
||||
if (cpucs_addr && !ezusb_cpucs(device, cpucs_addr, false))
|
||||
{
|
||||
ret = -1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* at least write the interrupt vectors (at 0x0000) for reset! */
|
||||
status = fseek(image, 0L, SEEK_SET);
|
||||
if (status < 0) {
|
||||
logerror("unable to rewind file %s\n", path);
|
||||
ret = status;
|
||||
goto exit;
|
||||
}
|
||||
if (verbose)
|
||||
logerror("2nd stage: write on-chip memory\n");
|
||||
status = parse_ihex(image, &ctx, is_external, ram_poke);
|
||||
if (status < 0) {
|
||||
logerror("unable to completely upload %s\n", path);
|
||||
ret = status;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose && (ctx.count != 0)) {
|
||||
logerror("... WROTE: %d bytes, %d segments, avg %d\n",
|
||||
(int)ctx.total, (int)ctx.count, (int)(ctx.total/ctx.count));
|
||||
}
|
||||
|
||||
/* if required, reset the CPU so it runs what we just uploaded */
|
||||
if (cpucs_addr && !ezusb_cpucs(device, cpucs_addr, true))
|
||||
ret = -1;
|
||||
|
||||
exit:
|
||||
fclose(image);
|
||||
return ret;
|
||||
}
|
||||
109
lib/libusb/examples/ezusb.h
Normal file
109
lib/libusb/examples/ezusb.h
Normal file
@@ -0,0 +1,109 @@
|
||||
#ifndef ezusb_H
|
||||
#define ezusb_H
|
||||
/*
|
||||
* Copyright © 2001 Stephen Williams (steve@icarus.com)
|
||||
* Copyright © 2002 David Brownell (dbrownell@users.sourceforge.net)
|
||||
* Copyright © 2013 Federico Manzan (f.manzan@gmail.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define FX_TYPE_UNDEFINED -1
|
||||
#define FX_TYPE_AN21 0 /* Original AnchorChips parts */
|
||||
#define FX_TYPE_FX1 1 /* Updated Cypress versions */
|
||||
#define FX_TYPE_FX2 2 /* USB 2.0 versions */
|
||||
#define FX_TYPE_FX2LP 3 /* Updated FX2 */
|
||||
#define FX_TYPE_FX3 4 /* USB 3.0 versions */
|
||||
#define FX_TYPE_MAX 5
|
||||
#define FX_TYPE_NAMES { "an21", "fx", "fx2", "fx2lp", "fx3" }
|
||||
|
||||
#define IMG_TYPE_UNDEFINED -1
|
||||
#define IMG_TYPE_HEX 0 /* Intel HEX */
|
||||
#define IMG_TYPE_IIC 1 /* Cypress 8051 IIC */
|
||||
#define IMG_TYPE_BIX 2 /* Cypress 8051 BIX */
|
||||
#define IMG_TYPE_IMG 3 /* Cypress IMG format */
|
||||
#define IMG_TYPE_MAX 4
|
||||
#define IMG_TYPE_NAMES { "Intel HEX", "Cypress 8051 IIC", "Cypress 8051 BIX", "Cypress IMG format" }
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Automatically identified devices (VID, PID, type, designation).
|
||||
* TODO: Could use some validation. Also where's the FX2?
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t vid;
|
||||
uint16_t pid;
|
||||
int type;
|
||||
const char* designation;
|
||||
} fx_known_device;
|
||||
|
||||
#define FX_KNOWN_DEVICES { \
|
||||
{ 0x0547, 0x2122, FX_TYPE_AN21, "Cypress EZ-USB (2122S)" },\
|
||||
{ 0x0547, 0x2125, FX_TYPE_AN21, "Cypress EZ-USB (2121S/2125S)" },\
|
||||
{ 0x0547, 0x2126, FX_TYPE_AN21, "Cypress EZ-USB (2126S)" },\
|
||||
{ 0x0547, 0x2131, FX_TYPE_AN21, "Cypress EZ-USB (2131Q/2131S/2135S)" },\
|
||||
{ 0x0547, 0x2136, FX_TYPE_AN21, "Cypress EZ-USB (2136S)" },\
|
||||
{ 0x0547, 0x2225, FX_TYPE_AN21, "Cypress EZ-USB (2225)" },\
|
||||
{ 0x0547, 0x2226, FX_TYPE_AN21, "Cypress EZ-USB (2226)" },\
|
||||
{ 0x0547, 0x2235, FX_TYPE_AN21, "Cypress EZ-USB (2235)" },\
|
||||
{ 0x0547, 0x2236, FX_TYPE_AN21, "Cypress EZ-USB (2236)" },\
|
||||
{ 0x04b4, 0x6473, FX_TYPE_FX1, "Cypress EZ-USB FX1" },\
|
||||
{ 0x04b4, 0x8613, FX_TYPE_FX2LP, "Cypress EZ-USB FX2LP (68013A/68014A/68015A/68016A)" }, \
|
||||
{ 0x04b4, 0x00f3, FX_TYPE_FX3, "Cypress FX3" },\
|
||||
}
|
||||
|
||||
/*
|
||||
* This function uploads the firmware from the given file into RAM.
|
||||
* Stage == 0 means this is a single stage load (or the first of
|
||||
* two stages). Otherwise it's the second of two stages; the
|
||||
* caller having preloaded the second stage loader.
|
||||
*
|
||||
* The target processor is reset at the end of this upload.
|
||||
*/
|
||||
extern int ezusb_load_ram(libusb_device_handle *device,
|
||||
const char *path, int fx_type, int img_type, int stage);
|
||||
|
||||
/*
|
||||
* This function uploads the firmware from the given file into EEPROM.
|
||||
* This uses the right CPUCS address to terminate the EEPROM load with
|
||||
* a reset command where FX parts behave differently than FX2 ones.
|
||||
* The configuration byte is as provided here (zero for an21xx parts)
|
||||
* and the EEPROM type is set so that the microcontroller will boot
|
||||
* from it.
|
||||
*
|
||||
* The caller must have preloaded a second stage loader that knows
|
||||
* how to respond to the EEPROM write request.
|
||||
*/
|
||||
extern int ezusb_load_eeprom(libusb_device_handle *device,
|
||||
const char *path, int fx_type, int img_type, int config);
|
||||
|
||||
/* Verbosity level (default 1). Can be increased or decreased with options v/q */
|
||||
extern int verbose;
|
||||
|
||||
extern void logerror(const char *format, ...) PRINTF_FORMAT(1, 2);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
310
lib/libusb/examples/fxload.c
Normal file
310
lib/libusb/examples/fxload.c
Normal file
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright © 2001 Stephen Williams (steve@icarus.com)
|
||||
* Copyright © 2001-2002 David Brownell (dbrownell@users.sourceforge.net)
|
||||
* Copyright © 2008 Roger Williams (rawqux@users.sourceforge.net)
|
||||
* Copyright © 2012 Pete Batard (pete@akeo.ie)
|
||||
* Copyright © 2013 Federico Manzan (f.manzan@gmail.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include "libusb.h"
|
||||
#include "ezusb.h"
|
||||
|
||||
#if !defined(_WIN32) || defined(__CYGWIN__)
|
||||
#include <syslog.h>
|
||||
static bool dosyslog = false;
|
||||
#include <strings.h>
|
||||
#define libusb_strcasecmp strcasecmp
|
||||
#else
|
||||
#define libusb_strcasecmp _stricmp
|
||||
#endif
|
||||
|
||||
#ifndef FXLOAD_VERSION
|
||||
#define FXLOAD_VERSION (__DATE__ " (libusb)")
|
||||
#endif
|
||||
|
||||
#ifndef ARRAYSIZE
|
||||
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
|
||||
#endif
|
||||
|
||||
void logerror(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
|
||||
#if !defined(_WIN32) || defined(__CYGWIN__)
|
||||
if (dosyslog)
|
||||
vsyslog(LOG_ERR, format, ap);
|
||||
else
|
||||
#endif
|
||||
vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static int print_usage(int error_code) {
|
||||
fprintf(stderr, "\nUsage: fxload [-v] [-V] [-t type] [-d vid:pid] [-p bus,addr] [-s loader] -i firmware\n");
|
||||
fprintf(stderr, " -i <path> -- Firmware to upload\n");
|
||||
fprintf(stderr, " -s <path> -- Second stage loader\n");
|
||||
fprintf(stderr, " -t <type> -- Target type: an21, fx, fx2, fx2lp, fx3\n");
|
||||
fprintf(stderr, " -d <vid:pid> -- Target device, as an USB VID:PID\n");
|
||||
fprintf(stderr, " -p <bus,addr> -- Target device, as a libusb bus number and device address path\n");
|
||||
fprintf(stderr, " -v -- Increase verbosity\n");
|
||||
fprintf(stderr, " -q -- Decrease verbosity (silent mode)\n");
|
||||
fprintf(stderr, " -V -- Print program version\n");
|
||||
return error_code;
|
||||
}
|
||||
|
||||
#define FIRMWARE 0
|
||||
#define LOADER 1
|
||||
int main(int argc, char*argv[])
|
||||
{
|
||||
fx_known_device known_device[] = FX_KNOWN_DEVICES;
|
||||
const char *path[] = { NULL, NULL };
|
||||
const char *device_id = NULL;
|
||||
const char *device_path = getenv("DEVICE");
|
||||
const char *type = NULL;
|
||||
const char *fx_name[FX_TYPE_MAX] = FX_TYPE_NAMES;
|
||||
const char *ext, *img_name[] = IMG_TYPE_NAMES;
|
||||
int fx_type = FX_TYPE_UNDEFINED, img_type[ARRAYSIZE(path)];
|
||||
int opt, status;
|
||||
unsigned int i, j;
|
||||
unsigned vid = 0, pid = 0;
|
||||
unsigned busnum = 0, devaddr = 0, _busnum, _devaddr;
|
||||
libusb_device *dev, **devs;
|
||||
libusb_device_handle *device = NULL;
|
||||
struct libusb_device_descriptor desc;
|
||||
|
||||
while ((opt = getopt(argc, argv, "qvV?hd:p:i:I:s:S:t:")) != EOF)
|
||||
switch (opt) {
|
||||
|
||||
case 'd':
|
||||
device_id = optarg;
|
||||
if (sscanf(device_id, "%x:%x" , &vid, &pid) != 2 ) {
|
||||
fputs ("please specify VID & PID as \"vid:pid\" in hexadecimal format\n", stderr);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
device_path = optarg;
|
||||
if (sscanf(device_path, "%u,%u", &busnum, &devaddr) != 2 ) {
|
||||
fputs ("please specify bus number & device number as \"bus,dev\" in decimal format\n", stderr);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
case 'I':
|
||||
path[FIRMWARE] = optarg;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
case 'S':
|
||||
path[LOADER] = optarg;
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
puts(FXLOAD_VERSION);
|
||||
return 0;
|
||||
|
||||
case 't':
|
||||
type = optarg;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
verbose--;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
case 'h':
|
||||
default:
|
||||
return print_usage(-1);
|
||||
|
||||
}
|
||||
|
||||
if (path[FIRMWARE] == NULL) {
|
||||
logerror("no firmware specified!\n");
|
||||
return print_usage(-1);
|
||||
}
|
||||
if ((device_id != NULL) && (device_path != NULL)) {
|
||||
logerror("only one of -d or -p can be specified\n");
|
||||
return print_usage(-1);
|
||||
}
|
||||
|
||||
/* determine the target type */
|
||||
if (type != NULL) {
|
||||
for (i=0; i<FX_TYPE_MAX; i++) {
|
||||
if (strcmp(type, fx_name[i]) == 0) {
|
||||
fx_type = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= FX_TYPE_MAX) {
|
||||
logerror("illegal microcontroller type: %s\n", type);
|
||||
return print_usage(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/* open the device using libusb */
|
||||
status = libusb_init_context(/*ctx=*/NULL, /*options=*/NULL, /*num_options=*/0);
|
||||
if (status < 0) {
|
||||
logerror("libusb_init_context() failed: %s\n", libusb_error_name(status));
|
||||
return -1;
|
||||
}
|
||||
libusb_set_option(NULL, LIBUSB_OPTION_LOG_LEVEL, verbose);
|
||||
|
||||
/* try to pick up missing parameters from known devices */
|
||||
if ((type == NULL) || (device_id == NULL) || (device_path != NULL)) {
|
||||
if (libusb_get_device_list(NULL, &devs) < 0) {
|
||||
logerror("libusb_get_device_list() failed: %s\n", libusb_error_name(status));
|
||||
goto err;
|
||||
}
|
||||
for (i=0; (dev=devs[i]) != NULL; i++) {
|
||||
_busnum = libusb_get_bus_number(dev);
|
||||
_devaddr = libusb_get_device_address(dev);
|
||||
if ((type != NULL) && (device_path != NULL)) {
|
||||
// if both a type and bus,addr were specified, we just need to find our match
|
||||
if ((libusb_get_bus_number(dev) == busnum) && (libusb_get_device_address(dev) == devaddr))
|
||||
break;
|
||||
} else {
|
||||
status = libusb_get_device_descriptor(dev, &desc);
|
||||
if (status >= 0) {
|
||||
if (verbose >= 3) {
|
||||
logerror("examining %04x:%04x (%d,%d)\n",
|
||||
desc.idVendor, desc.idProduct, _busnum, _devaddr);
|
||||
}
|
||||
for (j=0; j<ARRAYSIZE(known_device); j++) {
|
||||
if ((desc.idVendor == known_device[j].vid)
|
||||
&& (desc.idProduct == known_device[j].pid)) {
|
||||
if (// nothing was specified
|
||||
((type == NULL) && (device_id == NULL) && (device_path == NULL)) ||
|
||||
// vid:pid was specified and we have a match
|
||||
((type == NULL) && (device_id != NULL) && (vid == desc.idVendor) && (pid == desc.idProduct)) ||
|
||||
// bus,addr was specified and we have a match
|
||||
((type == NULL) && (device_path != NULL) && (busnum == _busnum) && (devaddr == _devaddr)) ||
|
||||
// type was specified and we have a match
|
||||
((type != NULL) && (device_id == NULL) && (device_path == NULL) && (fx_type == known_device[j].type)) ) {
|
||||
fx_type = known_device[j].type;
|
||||
vid = desc.idVendor;
|
||||
pid = desc.idProduct;
|
||||
busnum = _busnum;
|
||||
devaddr = _devaddr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (j < ARRAYSIZE(known_device)) {
|
||||
if (verbose)
|
||||
logerror("found device '%s' [%04x:%04x] (%d,%d)\n",
|
||||
known_device[j].designation, vid, pid, busnum, devaddr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dev == NULL) {
|
||||
libusb_free_device_list(devs, 1);
|
||||
libusb_exit(NULL);
|
||||
logerror("could not find a known device - please specify type and/or vid:pid and/or bus,dev\n");
|
||||
return print_usage(-1);
|
||||
}
|
||||
status = libusb_open(dev, &device);
|
||||
libusb_free_device_list(devs, 1);
|
||||
if (status < 0) {
|
||||
logerror("libusb_open() failed: %s\n", libusb_error_name(status));
|
||||
goto err;
|
||||
}
|
||||
} else if (device_id != NULL) {
|
||||
device = libusb_open_device_with_vid_pid(NULL, (uint16_t)vid, (uint16_t)pid);
|
||||
if (device == NULL) {
|
||||
logerror("libusb_open() failed\n");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/* We need to claim the first interface */
|
||||
libusb_set_auto_detach_kernel_driver(device, 1);
|
||||
status = libusb_claim_interface(device, 0);
|
||||
if (status != LIBUSB_SUCCESS) {
|
||||
libusb_close(device);
|
||||
logerror("libusb_claim_interface failed: %s\n", libusb_error_name(status));
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
logerror("microcontroller type: %s\n", fx_name[fx_type]);
|
||||
|
||||
for (i=0; i<ARRAYSIZE(path); i++) {
|
||||
if (path[i] != NULL) {
|
||||
ext = path[i] + strlen(path[i]) - 4;
|
||||
if ((libusb_strcasecmp(ext, ".hex") == 0) || (libusb_strcasecmp(ext, ".ihx") == 0))
|
||||
img_type[i] = IMG_TYPE_HEX;
|
||||
else if (libusb_strcasecmp(ext, ".iic") == 0)
|
||||
img_type[i] = IMG_TYPE_IIC;
|
||||
else if (libusb_strcasecmp(ext, ".bix") == 0)
|
||||
img_type[i] = IMG_TYPE_BIX;
|
||||
else if (libusb_strcasecmp(ext, ".img") == 0)
|
||||
img_type[i] = IMG_TYPE_IMG;
|
||||
else {
|
||||
logerror("%s is not a recognized image type\n", path[i]);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
if (verbose && path[i] != NULL)
|
||||
logerror("%s: type %s\n", path[i], img_name[img_type[i]]);
|
||||
}
|
||||
|
||||
if (path[LOADER] == NULL) {
|
||||
/* single stage, put into internal memory */
|
||||
if (verbose > 1)
|
||||
logerror("single stage: load on-chip memory\n");
|
||||
status = ezusb_load_ram(device, path[FIRMWARE], fx_type, img_type[FIRMWARE], 0);
|
||||
} else {
|
||||
/* two-stage, put loader into internal memory */
|
||||
if (verbose > 1)
|
||||
logerror("1st stage: load 2nd stage loader\n");
|
||||
status = ezusb_load_ram(device, path[LOADER], fx_type, img_type[LOADER], 0);
|
||||
if (status == 0) {
|
||||
/* two-stage, put firmware into internal memory */
|
||||
if (verbose > 1)
|
||||
logerror("2nd state: load on-chip memory\n");
|
||||
status = ezusb_load_ram(device, path[FIRMWARE], fx_type, img_type[FIRMWARE], 1);
|
||||
}
|
||||
}
|
||||
|
||||
libusb_release_interface(device, 0);
|
||||
libusb_close(device);
|
||||
libusb_exit(NULL);
|
||||
return status;
|
||||
err:
|
||||
libusb_exit(NULL);
|
||||
return -1;
|
||||
}
|
||||
147
lib/libusb/examples/hotplugtest.c
Normal file
147
lib/libusb/examples/hotplugtest.c
Normal file
@@ -0,0 +1,147 @@
|
||||
/* -*- Mode: C; indent-tabs-mode:t ; c-basic-offset:8 -*- */
|
||||
/*
|
||||
* libusb example program for hotplug API
|
||||
* Copyright © 2012-2013 Nathan Hjelm <hjelmn@mac.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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libusb.h"
|
||||
|
||||
int done = 0;
|
||||
libusb_device_handle *handle = NULL;
|
||||
|
||||
static int LIBUSB_CALL hotplug_callback(libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data)
|
||||
{
|
||||
struct libusb_device_descriptor desc;
|
||||
int rc;
|
||||
|
||||
(void)ctx;
|
||||
(void)dev;
|
||||
(void)event;
|
||||
(void)user_data;
|
||||
|
||||
rc = libusb_get_device_descriptor(dev, &desc);
|
||||
if (LIBUSB_SUCCESS == rc) {
|
||||
printf ("Device attached: %04x:%04x\n", desc.idVendor, desc.idProduct);
|
||||
} else {
|
||||
printf ("Device attached\n");
|
||||
fprintf (stderr, "Error getting device descriptor: %s\n",
|
||||
libusb_strerror((enum libusb_error)rc));
|
||||
}
|
||||
|
||||
if (handle) {
|
||||
libusb_close (handle);
|
||||
handle = NULL;
|
||||
}
|
||||
|
||||
rc = libusb_open (dev, &handle);
|
||||
if (LIBUSB_SUCCESS != rc) {
|
||||
fprintf (stderr, "No access to device: %s\n",
|
||||
libusb_strerror((enum libusb_error)rc));
|
||||
}
|
||||
|
||||
done++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int LIBUSB_CALL hotplug_callback_detach(libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data)
|
||||
{
|
||||
struct libusb_device_descriptor desc;
|
||||
int rc;
|
||||
|
||||
(void)ctx;
|
||||
(void)dev;
|
||||
(void)event;
|
||||
(void)user_data;
|
||||
|
||||
rc = libusb_get_device_descriptor(dev, &desc);
|
||||
if (LIBUSB_SUCCESS == rc) {
|
||||
printf ("Device detached: %04x:%04x\n", desc.idVendor, desc.idProduct);
|
||||
} else {
|
||||
printf ("Device detached\n");
|
||||
fprintf (stderr, "Error getting device descriptor: %s\n",
|
||||
libusb_strerror((enum libusb_error)rc));
|
||||
}
|
||||
|
||||
if (handle) {
|
||||
libusb_close (handle);
|
||||
handle = NULL;
|
||||
}
|
||||
|
||||
done++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
libusb_hotplug_callback_handle hp[2];
|
||||
int product_id, vendor_id, class_id;
|
||||
int rc;
|
||||
|
||||
vendor_id = (argc > 1) ? (int)strtol (argv[1], NULL, 0) : LIBUSB_HOTPLUG_MATCH_ANY;
|
||||
product_id = (argc > 2) ? (int)strtol (argv[2], NULL, 0) : LIBUSB_HOTPLUG_MATCH_ANY;
|
||||
class_id = (argc > 3) ? (int)strtol (argv[3], NULL, 0) : LIBUSB_HOTPLUG_MATCH_ANY;
|
||||
|
||||
rc = libusb_init_context(/*ctx=*/NULL, /*options=*/NULL, /*num_options=*/0);
|
||||
if (LIBUSB_SUCCESS != rc)
|
||||
{
|
||||
printf ("failed to initialise libusb: %s\n",
|
||||
libusb_strerror((enum libusb_error)rc));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!libusb_has_capability (LIBUSB_CAP_HAS_HOTPLUG)) {
|
||||
printf ("Hotplug capabilities are not supported on this platform\n");
|
||||
libusb_exit (NULL);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
rc = libusb_hotplug_register_callback (NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0, vendor_id,
|
||||
product_id, class_id, hotplug_callback, NULL, &hp[0]);
|
||||
if (LIBUSB_SUCCESS != rc) {
|
||||
fprintf (stderr, "Error registering callback 0\n");
|
||||
libusb_exit (NULL);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
rc = libusb_hotplug_register_callback (NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0, vendor_id,
|
||||
product_id,class_id, hotplug_callback_detach, NULL, &hp[1]);
|
||||
if (LIBUSB_SUCCESS != rc) {
|
||||
fprintf (stderr, "Error registering callback 1\n");
|
||||
libusb_exit (NULL);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
while (done < 2) {
|
||||
rc = libusb_handle_events (NULL);
|
||||
if (LIBUSB_SUCCESS != rc)
|
||||
printf ("libusb_handle_events() failed: %s\n",
|
||||
libusb_strerror((enum libusb_error)rc));
|
||||
}
|
||||
|
||||
if (handle) {
|
||||
libusb_close (handle);
|
||||
}
|
||||
|
||||
libusb_exit (NULL);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
73
lib/libusb/examples/listdevs.c
Normal file
73
lib/libusb/examples/listdevs.c
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* libusb example program to list devices on the bus
|
||||
* Copyright © 2007 Daniel Drake <dsd@gentoo.org>
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
|
||||
#include "libusb.h"
|
||||
|
||||
static void print_devs(libusb_device **devs)
|
||||
{
|
||||
libusb_device *dev;
|
||||
int i = 0, j = 0;
|
||||
uint8_t path[8];
|
||||
|
||||
while ((dev = devs[i++]) != NULL) {
|
||||
struct libusb_device_descriptor desc;
|
||||
int r = libusb_get_device_descriptor(dev, &desc);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "failed to get device descriptor");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("%04x:%04x (bus %d, device %d)",
|
||||
desc.idVendor, desc.idProduct,
|
||||
libusb_get_bus_number(dev), libusb_get_device_address(dev));
|
||||
|
||||
r = libusb_get_port_numbers(dev, path, sizeof(path));
|
||||
if (r > 0) {
|
||||
printf(" path: %d", path[0]);
|
||||
for (j = 1; j < r; j++)
|
||||
printf(".%d", path[j]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
libusb_device **devs;
|
||||
int r;
|
||||
ssize_t cnt;
|
||||
|
||||
r = libusb_init_context(/*ctx=*/NULL, /*options=*/NULL, /*num_options=*/0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
cnt = libusb_get_device_list(NULL, &devs);
|
||||
if (cnt < 0){
|
||||
libusb_exit(NULL);
|
||||
return (int) cnt;
|
||||
}
|
||||
|
||||
print_devs(devs);
|
||||
libusb_free_device_list(devs, 1);
|
||||
|
||||
libusb_exit(NULL);
|
||||
return 0;
|
||||
}
|
||||
228
lib/libusb/examples/sam3u_benchmark.c
Normal file
228
lib/libusb/examples/sam3u_benchmark.c
Normal file
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* libusb example program to measure Atmel SAM3U isochronous performance
|
||||
* Copyright (C) 2012 Harald Welte <laforge@gnumonks.org>
|
||||
*
|
||||
* Copied with the author's permission under LGPL-2.1 from
|
||||
* http://git.gnumonks.org/cgi-bin/gitweb.cgi?p=sam3u-tests.git;a=blob;f=usb-benchmark-project/host/benchmark.c;h=74959f7ee88f1597286cd435f312a8ff52c56b7e
|
||||
*
|
||||
* An Atmel SAM3U test firmware is also available in the above repository.
|
||||
*
|
||||
* 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 <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
|
||||
#include "libusb.h"
|
||||
|
||||
#define EP_DATA_IN 0x82
|
||||
#define EP_ISO_IN 0x86
|
||||
|
||||
static volatile sig_atomic_t do_exit = 0;
|
||||
static struct libusb_device_handle *devh = NULL;
|
||||
|
||||
static unsigned long num_bytes = 0, num_xfer = 0;
|
||||
static struct timeval tv_start;
|
||||
|
||||
static void get_timestamp(struct timeval *tv)
|
||||
{
|
||||
#if defined(PLATFORM_WINDOWS)
|
||||
static LARGE_INTEGER frequency;
|
||||
LARGE_INTEGER counter;
|
||||
|
||||
if (!frequency.QuadPart)
|
||||
QueryPerformanceFrequency(&frequency);
|
||||
|
||||
QueryPerformanceCounter(&counter);
|
||||
counter.QuadPart *= 1000000;
|
||||
counter.QuadPart /= frequency.QuadPart;
|
||||
|
||||
tv->tv_sec = (long)(counter.QuadPart / 1000000ULL);
|
||||
tv->tv_usec = (long)(counter.QuadPart % 1000000ULL);
|
||||
#elif defined(HAVE_CLOCK_GETTIME)
|
||||
struct timespec ts;
|
||||
|
||||
(void)clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
tv->tv_sec = ts.tv_sec;
|
||||
tv->tv_usec = (int)(ts.tv_nsec / 1000L);
|
||||
#else
|
||||
gettimeofday(tv, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void LIBUSB_CALL cb_xfr(struct libusb_transfer *xfr)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (xfr->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
fprintf(stderr, "transfer status %d\n", xfr->status);
|
||||
libusb_free_transfer(xfr);
|
||||
exit(3);
|
||||
}
|
||||
|
||||
if (xfr->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
|
||||
for (i = 0; i < xfr->num_iso_packets; i++) {
|
||||
struct libusb_iso_packet_descriptor *pack = &xfr->iso_packet_desc[i];
|
||||
|
||||
if (pack->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
fprintf(stderr, "Error: pack %d status %d\n", i, pack->status);
|
||||
exit(5);
|
||||
}
|
||||
|
||||
printf("pack%d length:%u, actual_length:%u\n", i, pack->length, pack->actual_length);
|
||||
}
|
||||
}
|
||||
|
||||
printf("length:%u, actual_length:%u\n", xfr->length, xfr->actual_length);
|
||||
for (i = 0; i < xfr->actual_length; i++) {
|
||||
printf("%02x", xfr->buffer[i]);
|
||||
if (i % 16)
|
||||
printf("\n");
|
||||
else if (i % 8)
|
||||
printf(" ");
|
||||
else
|
||||
printf(" ");
|
||||
}
|
||||
num_bytes += xfr->actual_length;
|
||||
num_xfer++;
|
||||
|
||||
if (libusb_submit_transfer(xfr) < 0) {
|
||||
fprintf(stderr, "error re-submitting URB\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static int benchmark_in(uint8_t ep)
|
||||
{
|
||||
static uint8_t buf[2048];
|
||||
static struct libusb_transfer *xfr;
|
||||
int num_iso_pack = 0;
|
||||
|
||||
if (ep == EP_ISO_IN)
|
||||
num_iso_pack = 16;
|
||||
|
||||
xfr = libusb_alloc_transfer(num_iso_pack);
|
||||
if (!xfr) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ep == EP_ISO_IN) {
|
||||
libusb_fill_iso_transfer(xfr, devh, ep, buf,
|
||||
sizeof(buf), num_iso_pack, cb_xfr, NULL, 0);
|
||||
libusb_set_iso_packet_lengths(xfr, sizeof(buf)/num_iso_pack);
|
||||
} else
|
||||
libusb_fill_bulk_transfer(xfr, devh, ep, buf,
|
||||
sizeof(buf), cb_xfr, NULL, 0);
|
||||
|
||||
get_timestamp(&tv_start);
|
||||
|
||||
/* NOTE: To reach maximum possible performance the program must
|
||||
* submit *multiple* transfers here, not just one.
|
||||
*
|
||||
* When only one transfer is submitted there is a gap in the bus
|
||||
* schedule from when the transfer completes until a new transfer
|
||||
* is submitted by the callback. This causes some jitter for
|
||||
* isochronous transfers and loss of throughput for bulk transfers.
|
||||
*
|
||||
* This is avoided by queueing multiple transfers in advance, so
|
||||
* that the host controller is always kept busy, and will schedule
|
||||
* more transfers on the bus while the callback is running for
|
||||
* transfers which have completed on the bus.
|
||||
*/
|
||||
|
||||
return libusb_submit_transfer(xfr);
|
||||
}
|
||||
|
||||
static void measure(void)
|
||||
{
|
||||
struct timeval tv_stop;
|
||||
unsigned long diff_msec;
|
||||
|
||||
get_timestamp(&tv_stop);
|
||||
|
||||
diff_msec = (tv_stop.tv_sec - tv_start.tv_sec) * 1000L;
|
||||
diff_msec += (tv_stop.tv_usec - tv_start.tv_usec) / 1000L;
|
||||
|
||||
printf("%lu transfers (total %lu bytes) in %lu milliseconds => %lu bytes/sec\n",
|
||||
num_xfer, num_bytes, diff_msec, (num_bytes * 1000L) / diff_msec);
|
||||
}
|
||||
|
||||
static void sig_hdlr(int signum)
|
||||
{
|
||||
(void)signum;
|
||||
|
||||
measure();
|
||||
do_exit = 1;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
#if defined(PLATFORM_POSIX)
|
||||
struct sigaction sigact;
|
||||
|
||||
sigact.sa_handler = sig_hdlr;
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = 0;
|
||||
(void)sigaction(SIGINT, &sigact, NULL);
|
||||
#else
|
||||
(void)signal(SIGINT, sig_hdlr);
|
||||
#endif
|
||||
|
||||
rc = libusb_init_context(/*ctx=*/NULL, /*options=*/NULL, /*num_options=*/0);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Error initializing libusb: %s\n", libusb_error_name(rc));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
devh = libusb_open_device_with_vid_pid(NULL, 0x16c0, 0x0763);
|
||||
if (!devh) {
|
||||
fprintf(stderr, "Error finding USB device\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = libusb_claim_interface(devh, 2);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Error claiming interface: %s\n", libusb_error_name(rc));
|
||||
goto out;
|
||||
}
|
||||
|
||||
benchmark_in(EP_ISO_IN);
|
||||
|
||||
while (!do_exit) {
|
||||
rc = libusb_handle_events(NULL);
|
||||
if (rc != LIBUSB_SUCCESS)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Measurement has already been done by the signal handler. */
|
||||
|
||||
libusb_release_interface(devh, 2);
|
||||
out:
|
||||
if (devh)
|
||||
libusb_close(devh);
|
||||
libusb_exit(NULL);
|
||||
return rc;
|
||||
}
|
||||
312
lib/libusb/examples/testlibusb.c
Normal file
312
lib/libusb/examples/testlibusb.c
Normal file
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
* Test suite program based of libusb-0.1-compat testlibusb
|
||||
* Copyright (c) 2013 Nathan Hjelm <hjelmn@mac.ccom>
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include "libusb.h"
|
||||
|
||||
int verbose = 0;
|
||||
|
||||
static void print_endpoint_comp(const struct libusb_ss_endpoint_companion_descriptor *ep_comp)
|
||||
{
|
||||
printf(" USB 3.0 Endpoint Companion:\n");
|
||||
printf(" bMaxBurst: %u\n", ep_comp->bMaxBurst);
|
||||
printf(" bmAttributes: %02xh\n", ep_comp->bmAttributes);
|
||||
printf(" wBytesPerInterval: %u\n", ep_comp->wBytesPerInterval);
|
||||
}
|
||||
|
||||
static void print_endpoint(const struct libusb_endpoint_descriptor *endpoint)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
printf(" Endpoint:\n");
|
||||
printf(" bEndpointAddress: %02xh\n", endpoint->bEndpointAddress);
|
||||
printf(" bmAttributes: %02xh\n", endpoint->bmAttributes);
|
||||
printf(" wMaxPacketSize: %u\n", endpoint->wMaxPacketSize);
|
||||
printf(" bInterval: %u\n", endpoint->bInterval);
|
||||
printf(" bRefresh: %u\n", endpoint->bRefresh);
|
||||
printf(" bSynchAddress: %u\n", endpoint->bSynchAddress);
|
||||
|
||||
for (i = 0; i < endpoint->extra_length;) {
|
||||
if (LIBUSB_DT_SS_ENDPOINT_COMPANION == endpoint->extra[i + 1]) {
|
||||
struct libusb_ss_endpoint_companion_descriptor *ep_comp;
|
||||
|
||||
ret = libusb_get_ss_endpoint_companion_descriptor(NULL, endpoint, &ep_comp);
|
||||
if (LIBUSB_SUCCESS != ret)
|
||||
continue;
|
||||
|
||||
print_endpoint_comp(ep_comp);
|
||||
|
||||
libusb_free_ss_endpoint_companion_descriptor(ep_comp);
|
||||
}
|
||||
|
||||
i += endpoint->extra[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void print_altsetting(const struct libusb_interface_descriptor *interface)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
printf(" Interface:\n");
|
||||
printf(" bInterfaceNumber: %u\n", interface->bInterfaceNumber);
|
||||
printf(" bAlternateSetting: %u\n", interface->bAlternateSetting);
|
||||
printf(" bNumEndpoints: %u\n", interface->bNumEndpoints);
|
||||
printf(" bInterfaceClass: %u\n", interface->bInterfaceClass);
|
||||
printf(" bInterfaceSubClass: %u\n", interface->bInterfaceSubClass);
|
||||
printf(" bInterfaceProtocol: %u\n", interface->bInterfaceProtocol);
|
||||
printf(" iInterface: %u\n", interface->iInterface);
|
||||
|
||||
for (i = 0; i < interface->bNumEndpoints; i++)
|
||||
print_endpoint(&interface->endpoint[i]);
|
||||
}
|
||||
|
||||
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(" bDevCapabilityType: %u\n", usb_2_0_ext_cap->bDevCapabilityType);
|
||||
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)
|
||||
{
|
||||
printf(" USB 3.0 Capabilities:\n");
|
||||
printf(" bDevCapabilityType: %u\n", ss_usb_cap->bDevCapabilityType);
|
||||
printf(" bmAttributes: %02xh\n", ss_usb_cap->bmAttributes);
|
||||
printf(" wSpeedSupported: %u\n", ss_usb_cap->wSpeedSupported);
|
||||
printf(" bFunctionalitySupport: %u\n", ss_usb_cap->bFunctionalitySupport);
|
||||
printf(" bU1devExitLat: %u\n", ss_usb_cap->bU1DevExitLat);
|
||||
printf(" bU2devExitLat: %u\n", ss_usb_cap->bU2DevExitLat);
|
||||
}
|
||||
|
||||
static void print_bos(libusb_device_handle *handle)
|
||||
{
|
||||
struct libusb_bos_descriptor *bos;
|
||||
uint8_t i;
|
||||
int ret;
|
||||
|
||||
ret = libusb_get_bos_descriptor(handle, &bos);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
printf(" Binary Object Store (BOS):\n");
|
||||
printf(" wTotalLength: %u\n", bos->wTotalLength);
|
||||
printf(" bNumDeviceCaps: %u\n", bos->bNumDeviceCaps);
|
||||
|
||||
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;
|
||||
|
||||
ret = libusb_get_usb_2_0_extension_descriptor(NULL, dev_cap, &usb_2_0_extension);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
print_2_0_ext_cap(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;
|
||||
|
||||
ret = libusb_get_ss_usb_device_capability_descriptor(NULL, dev_cap, &ss_dev_cap);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
print_ss_usb_cap(ss_dev_cap);
|
||||
libusb_free_ss_usb_device_capability_descriptor(ss_dev_cap);
|
||||
}
|
||||
}
|
||||
|
||||
libusb_free_bos_descriptor(bos);
|
||||
}
|
||||
|
||||
static void print_interface(const struct libusb_interface *interface)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < interface->num_altsetting; i++)
|
||||
print_altsetting(&interface->altsetting[i]);
|
||||
}
|
||||
|
||||
static void print_configuration(struct libusb_config_descriptor *config)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
printf(" Configuration:\n");
|
||||
printf(" wTotalLength: %u\n", config->wTotalLength);
|
||||
printf(" bNumInterfaces: %u\n", config->bNumInterfaces);
|
||||
printf(" bConfigurationValue: %u\n", config->bConfigurationValue);
|
||||
printf(" iConfiguration: %u\n", config->iConfiguration);
|
||||
printf(" bmAttributes: %02xh\n", config->bmAttributes);
|
||||
printf(" MaxPower: %u\n", config->MaxPower);
|
||||
|
||||
for (i = 0; i < config->bNumInterfaces; i++)
|
||||
print_interface(&config->interface[i]);
|
||||
}
|
||||
|
||||
static void print_device(libusb_device *dev, libusb_device_handle *handle)
|
||||
{
|
||||
struct libusb_device_descriptor desc;
|
||||
unsigned char string[256];
|
||||
const char *speed;
|
||||
int ret;
|
||||
uint8_t i;
|
||||
|
||||
switch (libusb_get_device_speed(dev)) {
|
||||
case LIBUSB_SPEED_LOW: speed = "1.5M"; break;
|
||||
case LIBUSB_SPEED_FULL: speed = "12M"; break;
|
||||
case LIBUSB_SPEED_HIGH: speed = "480M"; break;
|
||||
case LIBUSB_SPEED_SUPER: speed = "5G"; break;
|
||||
case LIBUSB_SPEED_SUPER_PLUS: speed = "10G"; break;
|
||||
case LIBUSB_SPEED_SUPER_PLUS_X2: speed = "20G"; break;
|
||||
default: speed = "Unknown";
|
||||
}
|
||||
|
||||
ret = libusb_get_device_descriptor(dev, &desc);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "failed to get device descriptor");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Dev (bus %u, device %u): %04X - %04X speed: %s\n",
|
||||
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) {
|
||||
ret = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, string, sizeof(string));
|
||||
if (ret > 0)
|
||||
printf(" Manufacturer: %s\n", (char *)string);
|
||||
}
|
||||
|
||||
if (desc.iProduct) {
|
||||
ret = libusb_get_string_descriptor_ascii(handle, desc.iProduct, string, sizeof(string));
|
||||
if (ret > 0)
|
||||
printf(" Product: %s\n", (char *)string);
|
||||
}
|
||||
|
||||
if (desc.iSerialNumber && verbose) {
|
||||
ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, string, sizeof(string));
|
||||
if (ret > 0)
|
||||
printf(" Serial Number: %s\n", (char *)string);
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
for (i = 0; i < desc.bNumConfigurations; i++) {
|
||||
struct libusb_config_descriptor *config;
|
||||
|
||||
ret = libusb_get_config_descriptor(dev, i, &config);
|
||||
if (LIBUSB_SUCCESS != ret) {
|
||||
printf(" Couldn't retrieve descriptors\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
print_configuration(config);
|
||||
|
||||
libusb_free_config_descriptor(config);
|
||||
}
|
||||
|
||||
if (handle && desc.bcdUSB >= 0x0201)
|
||||
print_bos(handle);
|
||||
}
|
||||
|
||||
if (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;
|
||||
}
|
||||
#else
|
||||
static int test_wrapped_device(const char *device_name)
|
||||
{
|
||||
(void)device_name;
|
||||
printf("Testing wrapped devices is not supported on your platform\n");
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const char *device_name = NULL;
|
||||
libusb_device **devs;
|
||||
ssize_t cnt;
|
||||
int r, i;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "-v")) {
|
||||
verbose = 1;
|
||||
} else if (!strcmp(argv[i], "-d") && (i + 1) < argc) {
|
||||
i++;
|
||||
device_name = argv[i];
|
||||
} else {
|
||||
printf("Usage %s [-v] [-d </dev/bus/usb/...>]\n", argv[0]);
|
||||
printf("Note use -d to test libusb_wrap_sys_device()\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
r = libusb_init_context(/*ctx=*/NULL, /*options=*/NULL, /*num_options=*/0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (device_name) {
|
||||
r = test_wrapped_device(device_name);
|
||||
} else {
|
||||
cnt = libusb_get_device_list(NULL, &devs);
|
||||
if (cnt < 0) {
|
||||
libusb_exit(NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; devs[i]; i++)
|
||||
print_device(devs[i], NULL);
|
||||
|
||||
libusb_free_device_list(devs, 1);
|
||||
}
|
||||
|
||||
libusb_exit(NULL);
|
||||
return r;
|
||||
}
|
||||
1256
lib/libusb/examples/xusb.c
Normal file
1256
lib/libusb/examples/xusb.c
Normal file
File diff suppressed because it is too large
Load Diff
11
lib/libusb/libusb-1.0.pc.in
Normal file
11
lib/libusb/libusb-1.0.pc.in
Normal file
@@ -0,0 +1,11 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: libusb-1.0
|
||||
Description: C API for USB device access from Linux, Mac OS X, Windows, OpenBSD/NetBSD and Solaris userspace
|
||||
Version: @VERSION@
|
||||
Libs: -L${libdir} -lusb-1.0
|
||||
Libs.private: @LIBS@
|
||||
Cflags: -I${includedir}/libusb-1.0
|
||||
98
lib/libusb/libusb/Makefile.am
Normal file
98
lib/libusb/libusb/Makefile.am
Normal file
@@ -0,0 +1,98 @@
|
||||
AUTOMAKE_OPTIONS = subdir-objects
|
||||
|
||||
AM_CFLAGS += -fvisibility=hidden $(THREAD_CFLAGS)
|
||||
AM_CXXFLAGS += -fvisibility=hidden $(THREAD_CFLAGS)
|
||||
|
||||
lib_LTLIBRARIES = libusb-1.0.la
|
||||
|
||||
POSIX_PLATFORM_SRC = os/events_posix.h os/events_posix.c \
|
||||
os/threads_posix.h os/threads_posix.c
|
||||
WINDOWS_PLATFORM_SRC = os/events_windows.h os/events_windows.c \
|
||||
os/threads_windows.h os/threads_windows.c
|
||||
|
||||
if PLATFORM_POSIX
|
||||
PLATFORM_SRC = $(POSIX_PLATFORM_SRC)
|
||||
else
|
||||
PLATFORM_SRC = $(WINDOWS_PLATFORM_SRC)
|
||||
endif
|
||||
|
||||
OS_DARWIN_SRC = os/darwin_usb.h os/darwin_usb.c
|
||||
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_EMSCRIPTEN_SRC = os/emscripten_webusb.cpp
|
||||
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_winusb.h os/windows_winusb.c
|
||||
|
||||
if OS_DARWIN
|
||||
OS_SRC = $(OS_DARWIN_SRC)
|
||||
endif
|
||||
|
||||
noinst_LTLIBRARIES =
|
||||
|
||||
if OS_HAIKU
|
||||
noinst_LTLIBRARIES += libusb_haiku.la
|
||||
libusb_haiku_la_SOURCES = $(OS_HAIKU_SRC)
|
||||
libusb_1_0_la_LIBADD = libusb_haiku.la
|
||||
endif
|
||||
|
||||
if OS_LINUX
|
||||
OS_SRC = $(OS_LINUX_SRC)
|
||||
if USE_UDEV
|
||||
OS_SRC += os/linux_udev.c
|
||||
else
|
||||
OS_SRC += os/linux_netlink.c
|
||||
endif
|
||||
endif
|
||||
|
||||
if OS_EMSCRIPTEN
|
||||
noinst_LTLIBRARIES += libusb_emscripten.la
|
||||
libusb_emscripten_la_SOURCES = $(OS_EMSCRIPTEN_SRC)
|
||||
AM_CXXFLAGS += -std=c++20
|
||||
libusb_1_0_la_LIBADD = libusb_emscripten.la
|
||||
endif
|
||||
|
||||
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
|
||||
all-local: .libs/libusb-1.0.dll.a
|
||||
# Rebuild the import lib from the .def so that MS and MinGW DLLs can be interchanged
|
||||
.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
|
||||
|
||||
libusb_1_0_la_LDFLAGS = $(LT_LDFLAGS) $(EXTRA_LDFLAGS)
|
||||
libusb_1_0_la_SOURCES = libusbi.h version.h version_nano.h \
|
||||
core.c descriptor.c hotplug.c io.c strerror.c sync.c \
|
||||
$(PLATFORM_SRC) $(OS_SRC)
|
||||
|
||||
pkginclude_HEADERS = libusb.h
|
||||
26
lib/libusb/libusb/Makefile.am.extra
Normal file
26
lib/libusb/libusb/Makefile.am.extra
Normal 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
|
||||
2932
lib/libusb/libusb/core.c
Normal file
2932
lib/libusb/libusb/core.c
Normal file
File diff suppressed because it is too large
Load Diff
1532
lib/libusb/libusb/descriptor.c
Normal file
1532
lib/libusb/libusb/descriptor.c
Normal file
File diff suppressed because it is too large
Load Diff
489
lib/libusb/libusb/hotplug.c
Normal file
489
lib/libusb/libusb/hotplug.c
Normal file
@@ -0,0 +1,489 @@
|
||||
/* -*- Mode: C; indent-tabs-mode:t ; c-basic-offset:8 -*- */
|
||||
/*
|
||||
* Hotplug functions for libusb
|
||||
* Copyright © 2012-2021 Nathan Hjelm <hjelmn@mac.com>
|
||||
* Copyright © 2012-2013 Peter Stuge <peter@stuge.se>
|
||||
*
|
||||
* 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"
|
||||
|
||||
/**
|
||||
* @defgroup libusb_hotplug Device hotplug event notification
|
||||
* This page details how to use the libusb hotplug interface, where available.
|
||||
*
|
||||
* Be mindful that not all platforms currently implement hotplug notification and
|
||||
* that you should first call on \ref libusb_has_capability() with parameter
|
||||
* \ref LIBUSB_CAP_HAS_HOTPLUG to confirm that hotplug support is available.
|
||||
*
|
||||
* \page libusb_hotplug Device hotplug event notification
|
||||
*
|
||||
* \section hotplug_intro Introduction
|
||||
*
|
||||
* Version 1.0.16, \ref LIBUSBX_API_VERSION >= 0x01000102, has added support
|
||||
* for hotplug events on <b>some</b> platforms (you should test if your platform
|
||||
* supports hotplug notification by calling \ref libusb_has_capability() with
|
||||
* parameter \ref LIBUSB_CAP_HAS_HOTPLUG).
|
||||
*
|
||||
* This interface allows you to request notification for the arrival and departure
|
||||
* of matching USB devices.
|
||||
*
|
||||
* To receive hotplug notification you register a callback by calling
|
||||
* \ref libusb_hotplug_register_callback(). This function will optionally return
|
||||
* a callback handle that can be passed to \ref libusb_hotplug_deregister_callback().
|
||||
*
|
||||
* A callback function must return an int (0 or 1) indicating whether the callback is
|
||||
* expecting additional events. Returning 0 will rearm the callback and 1 will cause
|
||||
* the callback to be deregistered. Note that when callbacks are called from
|
||||
* libusb_hotplug_register_callback() because of the \ref LIBUSB_HOTPLUG_ENUMERATE
|
||||
* flag, the callback return value is ignored. In other words, you cannot cause a
|
||||
* callback to be deregistered by returning 1 when it is called from
|
||||
* libusb_hotplug_register_callback().
|
||||
*
|
||||
* Callbacks for a particular context are automatically deregistered by libusb_exit().
|
||||
*
|
||||
* As of 1.0.16 there are two supported hotplug events:
|
||||
* - LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED: A device has arrived and is ready to use
|
||||
* - LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT: A device has left and is no longer available
|
||||
*
|
||||
* A hotplug event can listen for either or both of these events.
|
||||
*
|
||||
* Note: If you receive notification that a device has left and you have any
|
||||
* libusb_device_handles for the device it is up to you to call libusb_close()
|
||||
* on each device handle to free up any remaining resources associated with the device.
|
||||
* Once a device has left any libusb_device_handle associated with the device
|
||||
* are invalid and will remain so even if the device comes back.
|
||||
*
|
||||
* When handling a LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED event it is considered
|
||||
* safe to call any libusb function that takes a libusb_device. It also safe to
|
||||
* open a device and submit asynchronous transfers. However, most other functions
|
||||
* that take a libusb_device_handle are <b>not</b> safe to call. Examples of such
|
||||
* functions are any of the \ref libusb_syncio "synchronous API" functions or the blocking
|
||||
* functions that retrieve various \ref libusb_desc "USB descriptors". These functions must
|
||||
* be used outside of the context of the hotplug callback.
|
||||
*
|
||||
* When handling a LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT event the only safe function
|
||||
* is libusb_get_device_descriptor().
|
||||
*
|
||||
* The following code provides an example of the usage of the hotplug interface:
|
||||
\code
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <libusb.h>
|
||||
|
||||
static int count = 0;
|
||||
|
||||
int hotplug_callback(struct libusb_context *ctx, struct libusb_device *dev,
|
||||
libusb_hotplug_event event, void *user_data) {
|
||||
static libusb_device_handle *dev_handle = NULL;
|
||||
struct libusb_device_descriptor desc;
|
||||
int rc;
|
||||
|
||||
(void)libusb_get_device_descriptor(dev, &desc);
|
||||
|
||||
if (LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED == event) {
|
||||
rc = libusb_open(dev, &dev_handle);
|
||||
if (LIBUSB_SUCCESS != rc) {
|
||||
printf("Could not open USB device\n");
|
||||
}
|
||||
} else if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == event) {
|
||||
if (dev_handle) {
|
||||
libusb_close(dev_handle);
|
||||
dev_handle = NULL;
|
||||
}
|
||||
} else {
|
||||
printf("Unhandled event %d\n", event);
|
||||
}
|
||||
count++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main (void) {
|
||||
libusb_hotplug_callback_handle callback_handle;
|
||||
int rc;
|
||||
|
||||
libusb_init_context(NULL, NULL, 0);
|
||||
|
||||
rc = libusb_hotplug_register_callback(NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED |
|
||||
LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0, 0x045a, 0x5005,
|
||||
LIBUSB_HOTPLUG_MATCH_ANY, hotplug_callback, NULL,
|
||||
&callback_handle);
|
||||
if (LIBUSB_SUCCESS != rc) {
|
||||
printf("Error creating a hotplug callback\n");
|
||||
libusb_exit(NULL);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
while (count < 2) {
|
||||
libusb_handle_events_completed(NULL, NULL);
|
||||
nanosleep(&(struct timespec){0, 10000000UL}, NULL);
|
||||
}
|
||||
|
||||
libusb_hotplug_deregister_callback(NULL, callback_handle);
|
||||
libusb_exit(NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
|
||||
#define VALID_HOTPLUG_EVENTS \
|
||||
(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | \
|
||||
LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT)
|
||||
|
||||
#define VALID_HOTPLUG_FLAGS \
|
||||
(LIBUSB_HOTPLUG_ENUMERATE)
|
||||
|
||||
void usbi_hotplug_init(struct libusb_context *ctx)
|
||||
{
|
||||
/* check for hotplug support */
|
||||
if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG))
|
||||
return;
|
||||
|
||||
usbi_mutex_init(&ctx->hotplug_cbs_lock);
|
||||
list_init(&ctx->hotplug_cbs);
|
||||
ctx->next_hotplug_cb_handle = 1;
|
||||
usbi_atomic_store(&ctx->hotplug_ready, 1);
|
||||
}
|
||||
|
||||
static void usbi_recursively_remove_parents(struct libusb_device *dev, struct libusb_device *next_dev)
|
||||
{
|
||||
if (dev && dev->parent_dev) {
|
||||
if (usbi_atomic_load(&dev->parent_dev->refcnt) == 1) {
|
||||
/* The parent was processed before this device in the list and
|
||||
* therefore has its ref count already decremented for its own ref.
|
||||
* The only remaining counted ref comes from its remaining single child.
|
||||
* It will thus be released when its child will be released. So we
|
||||
* can remove it from the list. This is safe as parent_dev cannot be
|
||||
* equal to next_dev given that we know at this point that it was
|
||||
* previously seen in the list. */
|
||||
assert (dev->parent_dev != next_dev);
|
||||
if (dev->parent_dev->list.next && dev->parent_dev->list.prev) {
|
||||
list_del(&dev->parent_dev->list);
|
||||
}
|
||||
}
|
||||
|
||||
usbi_recursively_remove_parents(dev->parent_dev, next_dev);
|
||||
}
|
||||
}
|
||||
|
||||
void usbi_hotplug_exit(struct libusb_context *ctx)
|
||||
{
|
||||
struct usbi_hotplug_callback *hotplug_cb, *next_cb;
|
||||
struct usbi_hotplug_message *msg;
|
||||
struct libusb_device *dev, *next_dev;
|
||||
|
||||
/* check for hotplug support */
|
||||
if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG))
|
||||
return;
|
||||
|
||||
if (!usbi_atomic_load(&ctx->hotplug_ready))
|
||||
return;
|
||||
|
||||
/* free all registered hotplug callbacks */
|
||||
for_each_hotplug_cb_safe(ctx, hotplug_cb, next_cb) {
|
||||
list_del(&hotplug_cb->list);
|
||||
free(hotplug_cb);
|
||||
}
|
||||
|
||||
/* free all pending hotplug messages */
|
||||
while (!list_empty(&ctx->hotplug_msgs)) {
|
||||
msg = list_first_entry(&ctx->hotplug_msgs, struct usbi_hotplug_message, list);
|
||||
|
||||
/* if the device left, the message holds a reference
|
||||
* and we must drop it */
|
||||
if (msg->event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT)
|
||||
libusb_unref_device(msg->device);
|
||||
|
||||
list_del(&msg->list);
|
||||
free(msg);
|
||||
}
|
||||
|
||||
usbi_mutex_lock(&ctx->usb_devs_lock); /* hotplug thread might still be processing an already triggered event, possibly accessing this list as well */
|
||||
/* free all discovered devices */
|
||||
for_each_device_safe(ctx, dev, next_dev) {
|
||||
/* remove the device from the usb_devs list only if there are no
|
||||
* references held, otherwise leave it on the list so that a
|
||||
* warning message will be shown */
|
||||
if (usbi_atomic_load(&dev->refcnt) == 1) {
|
||||
list_del(&dev->list);
|
||||
}
|
||||
|
||||
usbi_recursively_remove_parents(dev, next_dev);
|
||||
|
||||
libusb_unref_device(dev);
|
||||
}
|
||||
usbi_mutex_unlock(&ctx->usb_devs_lock);
|
||||
|
||||
usbi_mutex_destroy(&ctx->hotplug_cbs_lock);
|
||||
}
|
||||
|
||||
static int usbi_hotplug_match_cb(struct libusb_device *dev,
|
||||
libusb_hotplug_event event, struct usbi_hotplug_callback *hotplug_cb)
|
||||
{
|
||||
if (!(hotplug_cb->flags & event)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((hotplug_cb->flags & USBI_HOTPLUG_VENDOR_ID_VALID) &&
|
||||
hotplug_cb->vendor_id != dev->device_descriptor.idVendor) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((hotplug_cb->flags & USBI_HOTPLUG_PRODUCT_ID_VALID) &&
|
||||
hotplug_cb->product_id != dev->device_descriptor.idProduct) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((hotplug_cb->flags & USBI_HOTPLUG_DEV_CLASS_VALID) &&
|
||||
hotplug_cb->dev_class != dev->device_descriptor.bDeviceClass) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return hotplug_cb->cb(DEVICE_CTX(dev), dev, event, hotplug_cb->user_data);
|
||||
}
|
||||
|
||||
void usbi_hotplug_notification(struct libusb_context *ctx, struct libusb_device *dev,
|
||||
libusb_hotplug_event event)
|
||||
{
|
||||
struct usbi_hotplug_message *msg;
|
||||
unsigned int event_flags;
|
||||
|
||||
/* Only generate a notification if hotplug is ready. This prevents hotplug
|
||||
* notifications from being generated during initial enumeration or if the
|
||||
* backend does not support hotplug. */
|
||||
if (!usbi_atomic_load(&ctx->hotplug_ready))
|
||||
return;
|
||||
|
||||
msg = calloc(1, sizeof(*msg));
|
||||
if (!msg) {
|
||||
usbi_err(ctx, "error allocating hotplug message");
|
||||
return;
|
||||
}
|
||||
|
||||
msg->event = event;
|
||||
msg->device = dev;
|
||||
|
||||
/* Take the event data lock and add this message to the list.
|
||||
* Only signal an event if there are no prior pending events. */
|
||||
usbi_mutex_lock(&ctx->event_data_lock);
|
||||
event_flags = ctx->event_flags;
|
||||
ctx->event_flags |= USBI_EVENT_HOTPLUG_MSG_PENDING;
|
||||
list_add_tail(&msg->list, &ctx->hotplug_msgs);
|
||||
if (!event_flags)
|
||||
usbi_signal_event(&ctx->event);
|
||||
usbi_mutex_unlock(&ctx->event_data_lock);
|
||||
}
|
||||
|
||||
void usbi_hotplug_process(struct libusb_context *ctx, struct list_head *hotplug_msgs)
|
||||
{
|
||||
struct usbi_hotplug_callback *hotplug_cb, *next_cb;
|
||||
struct usbi_hotplug_message *msg;
|
||||
int r;
|
||||
|
||||
usbi_mutex_lock(&ctx->hotplug_cbs_lock);
|
||||
|
||||
/* dispatch all pending hotplug messages */
|
||||
while (!list_empty(hotplug_msgs)) {
|
||||
msg = list_first_entry(hotplug_msgs, struct usbi_hotplug_message, list);
|
||||
|
||||
for_each_hotplug_cb_safe(ctx, hotplug_cb, next_cb) {
|
||||
/* skip callbacks that have unregistered */
|
||||
if (hotplug_cb->flags & USBI_HOTPLUG_NEEDS_FREE)
|
||||
continue;
|
||||
|
||||
usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
|
||||
r = usbi_hotplug_match_cb(msg->device, msg->event, hotplug_cb);
|
||||
usbi_mutex_lock(&ctx->hotplug_cbs_lock);
|
||||
|
||||
if (r) {
|
||||
list_del(&hotplug_cb->list);
|
||||
free(hotplug_cb);
|
||||
}
|
||||
}
|
||||
|
||||
/* if the device left, the message holds a reference
|
||||
* and we must drop it */
|
||||
if (msg->event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT)
|
||||
libusb_unref_device(msg->device);
|
||||
|
||||
list_del(&msg->list);
|
||||
free(msg);
|
||||
}
|
||||
|
||||
/* free any callbacks that have unregistered */
|
||||
for_each_hotplug_cb_safe(ctx, hotplug_cb, next_cb) {
|
||||
if (hotplug_cb->flags & USBI_HOTPLUG_NEEDS_FREE) {
|
||||
usbi_dbg(ctx, "freeing hotplug cb %p with handle %d",
|
||||
(void *) hotplug_cb, hotplug_cb->handle);
|
||||
list_del(&hotplug_cb->list);
|
||||
free(hotplug_cb);
|
||||
}
|
||||
}
|
||||
|
||||
usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
|
||||
}
|
||||
|
||||
int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx,
|
||||
int events, int flags,
|
||||
int vendor_id, int product_id, int dev_class,
|
||||
libusb_hotplug_callback_fn cb_fn, void *user_data,
|
||||
libusb_hotplug_callback_handle *callback_handle)
|
||||
{
|
||||
struct usbi_hotplug_callback *hotplug_cb;
|
||||
|
||||
/* check for sane values */
|
||||
if (!events || (~VALID_HOTPLUG_EVENTS & events) ||
|
||||
(~VALID_HOTPLUG_FLAGS & flags) ||
|
||||
(LIBUSB_HOTPLUG_MATCH_ANY != vendor_id && (~0xffff & vendor_id)) ||
|
||||
(LIBUSB_HOTPLUG_MATCH_ANY != product_id && (~0xffff & product_id)) ||
|
||||
(LIBUSB_HOTPLUG_MATCH_ANY != dev_class && (~0xff & dev_class)) ||
|
||||
!cb_fn) {
|
||||
return LIBUSB_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
/* check for hotplug support */
|
||||
if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG))
|
||||
return LIBUSB_ERROR_NOT_SUPPORTED;
|
||||
|
||||
ctx = usbi_get_context(ctx);
|
||||
|
||||
hotplug_cb = calloc(1, sizeof(*hotplug_cb));
|
||||
if (!hotplug_cb)
|
||||
return LIBUSB_ERROR_NO_MEM;
|
||||
|
||||
hotplug_cb->flags = (uint8_t)events;
|
||||
if (LIBUSB_HOTPLUG_MATCH_ANY != vendor_id) {
|
||||
hotplug_cb->flags |= USBI_HOTPLUG_VENDOR_ID_VALID;
|
||||
hotplug_cb->vendor_id = (uint16_t)vendor_id;
|
||||
}
|
||||
if (LIBUSB_HOTPLUG_MATCH_ANY != product_id) {
|
||||
hotplug_cb->flags |= USBI_HOTPLUG_PRODUCT_ID_VALID;
|
||||
hotplug_cb->product_id = (uint16_t)product_id;
|
||||
}
|
||||
if (LIBUSB_HOTPLUG_MATCH_ANY != dev_class) {
|
||||
hotplug_cb->flags |= USBI_HOTPLUG_DEV_CLASS_VALID;
|
||||
hotplug_cb->dev_class = (uint8_t)dev_class;
|
||||
}
|
||||
hotplug_cb->cb = cb_fn;
|
||||
hotplug_cb->user_data = user_data;
|
||||
|
||||
usbi_mutex_lock(&ctx->hotplug_cbs_lock);
|
||||
|
||||
/* protect the handle by the context hotplug lock */
|
||||
hotplug_cb->handle = ctx->next_hotplug_cb_handle++;
|
||||
|
||||
/* handle the unlikely case of overflow */
|
||||
if (ctx->next_hotplug_cb_handle < 0)
|
||||
ctx->next_hotplug_cb_handle = 1;
|
||||
|
||||
list_add(&hotplug_cb->list, &ctx->hotplug_cbs);
|
||||
|
||||
usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
|
||||
|
||||
usbi_dbg(ctx, "new hotplug cb %p with handle %d",
|
||||
(void *) hotplug_cb, hotplug_cb->handle);
|
||||
|
||||
if ((flags & LIBUSB_HOTPLUG_ENUMERATE) && (events & LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED)) {
|
||||
ssize_t i, len;
|
||||
struct libusb_device **devs;
|
||||
|
||||
len = libusb_get_device_list(ctx, &devs);
|
||||
if (len < 0) {
|
||||
libusb_hotplug_deregister_callback(ctx, hotplug_cb->handle);
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
usbi_hotplug_match_cb(devs[i],
|
||||
LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED,
|
||||
hotplug_cb);
|
||||
}
|
||||
|
||||
libusb_free_device_list(devs, 1);
|
||||
}
|
||||
|
||||
if (callback_handle)
|
||||
*callback_handle = hotplug_cb->handle;
|
||||
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
void API_EXPORTED libusb_hotplug_deregister_callback(libusb_context *ctx,
|
||||
libusb_hotplug_callback_handle callback_handle)
|
||||
{
|
||||
struct usbi_hotplug_callback *hotplug_cb;
|
||||
int deregistered = 0;
|
||||
|
||||
/* check for hotplug support */
|
||||
if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG))
|
||||
return;
|
||||
|
||||
usbi_dbg(ctx, "deregister hotplug cb %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) {
|
||||
/* mark this callback for deregistration */
|
||||
hotplug_cb->flags |= USBI_HOTPLUG_NEEDS_FREE;
|
||||
deregistered = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
|
||||
|
||||
if (deregistered) {
|
||||
unsigned int event_flags;
|
||||
|
||||
usbi_mutex_lock(&ctx->event_data_lock);
|
||||
event_flags = ctx->event_flags;
|
||||
ctx->event_flags |= USBI_EVENT_HOTPLUG_CB_DEREGISTERED;
|
||||
if (!event_flags)
|
||||
usbi_signal_event(&ctx->event);
|
||||
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 usbi_hotplug_callback *hotplug_cb;
|
||||
void *user_data = NULL;
|
||||
|
||||
/* check for hotplug support */
|
||||
if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG))
|
||||
return NULL;
|
||||
|
||||
usbi_dbg(ctx, "get hotplug cb %d user data", 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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
|
||||
|
||||
return user_data;
|
||||
}
|
||||
2865
lib/libusb/libusb/io.c
Normal file
2865
lib/libusb/libusb/io.c
Normal file
File diff suppressed because it is too large
Load Diff
199
lib/libusb/libusb/libusb-1.0.def
Normal file
199
lib/libusb/libusb/libusb-1.0.def
Normal file
@@ -0,0 +1,199 @@
|
||||
LIBRARY "libusb-1.0.dll"
|
||||
EXPORTS
|
||||
libusb_alloc_streams
|
||||
libusb_alloc_streams@16 = libusb_alloc_streams
|
||||
libusb_alloc_transfer
|
||||
libusb_alloc_transfer@4 = libusb_alloc_transfer
|
||||
libusb_attach_kernel_driver
|
||||
libusb_attach_kernel_driver@8 = libusb_attach_kernel_driver
|
||||
libusb_bulk_transfer
|
||||
libusb_bulk_transfer@24 = libusb_bulk_transfer
|
||||
libusb_cancel_transfer
|
||||
libusb_cancel_transfer@4 = libusb_cancel_transfer
|
||||
libusb_claim_interface
|
||||
libusb_claim_interface@8 = libusb_claim_interface
|
||||
libusb_clear_halt
|
||||
libusb_clear_halt@8 = libusb_clear_halt
|
||||
libusb_close
|
||||
libusb_close@4 = libusb_close
|
||||
libusb_control_transfer
|
||||
libusb_control_transfer@32 = libusb_control_transfer
|
||||
libusb_detach_kernel_driver
|
||||
libusb_detach_kernel_driver@8 = libusb_detach_kernel_driver
|
||||
libusb_dev_mem_alloc
|
||||
libusb_dev_mem_alloc@8 = libusb_dev_mem_alloc
|
||||
libusb_dev_mem_free
|
||||
libusb_dev_mem_free@12 = libusb_dev_mem_free
|
||||
libusb_error_name
|
||||
libusb_error_name@4 = libusb_error_name
|
||||
libusb_event_handler_active
|
||||
libusb_event_handler_active@4 = libusb_event_handler_active
|
||||
libusb_event_handling_ok
|
||||
libusb_event_handling_ok@4 = libusb_event_handling_ok
|
||||
libusb_exit
|
||||
libusb_exit@4 = libusb_exit
|
||||
libusb_free_bos_descriptor
|
||||
libusb_free_bos_descriptor@4 = libusb_free_bos_descriptor
|
||||
libusb_free_config_descriptor
|
||||
libusb_free_config_descriptor@4 = libusb_free_config_descriptor
|
||||
libusb_free_container_id_descriptor
|
||||
libusb_free_container_id_descriptor@4 = libusb_free_container_id_descriptor
|
||||
libusb_free_device_list
|
||||
libusb_free_device_list@8 = libusb_free_device_list
|
||||
libusb_free_interface_association_descriptors
|
||||
libusb_free_interface_association_descriptors@4 = libusb_free_interface_association_descriptors
|
||||
libusb_free_platform_descriptor
|
||||
libusb_free_platform_descriptor@4 = libusb_free_platform_descriptor
|
||||
libusb_free_pollfds
|
||||
libusb_free_pollfds@4 = libusb_free_pollfds
|
||||
libusb_free_ss_endpoint_companion_descriptor
|
||||
libusb_free_ss_endpoint_companion_descriptor@4 = libusb_free_ss_endpoint_companion_descriptor
|
||||
libusb_free_ss_usb_device_capability_descriptor
|
||||
libusb_free_ss_usb_device_capability_descriptor@4 = libusb_free_ss_usb_device_capability_descriptor
|
||||
libusb_free_ssplus_usb_device_capability_descriptor
|
||||
libusb_free_ssplus_usb_device_capability_descriptor@4 = libusb_free_ssplus_usb_device_capability_descriptor
|
||||
libusb_free_streams
|
||||
libusb_free_streams@12 = libusb_free_streams
|
||||
libusb_free_transfer
|
||||
libusb_free_transfer@4 = libusb_free_transfer
|
||||
libusb_free_usb_2_0_extension_descriptor
|
||||
libusb_free_usb_2_0_extension_descriptor@4 = libusb_free_usb_2_0_extension_descriptor
|
||||
libusb_get_active_config_descriptor
|
||||
libusb_get_active_config_descriptor@8 = libusb_get_active_config_descriptor
|
||||
libusb_get_active_interface_association_descriptors
|
||||
libusb_get_active_interface_association_descriptors@8 = libusb_get_active_interface_association_descriptors
|
||||
libusb_get_bos_descriptor
|
||||
libusb_get_bos_descriptor@8 = libusb_get_bos_descriptor
|
||||
libusb_get_bus_number
|
||||
libusb_get_bus_number@4 = libusb_get_bus_number
|
||||
libusb_get_config_descriptor
|
||||
libusb_get_config_descriptor@12 = libusb_get_config_descriptor
|
||||
libusb_get_config_descriptor_by_value
|
||||
libusb_get_config_descriptor_by_value@12 = libusb_get_config_descriptor_by_value
|
||||
libusb_get_configuration
|
||||
libusb_get_configuration@8 = libusb_get_configuration
|
||||
libusb_get_container_id_descriptor
|
||||
libusb_get_container_id_descriptor@12 = libusb_get_container_id_descriptor
|
||||
libusb_get_device
|
||||
libusb_get_device@4 = libusb_get_device
|
||||
libusb_get_device_address
|
||||
libusb_get_device_address@4 = libusb_get_device_address
|
||||
libusb_get_device_descriptor
|
||||
libusb_get_device_descriptor@8 = libusb_get_device_descriptor
|
||||
libusb_get_device_list
|
||||
libusb_get_device_list@8 = libusb_get_device_list
|
||||
libusb_get_device_speed
|
||||
libusb_get_device_speed@4 = libusb_get_device_speed
|
||||
libusb_get_interface_association_descriptors
|
||||
libusb_get_interface_association_descriptors@12 = libusb_get_interface_association_descriptors
|
||||
libusb_get_max_alt_packet_size
|
||||
libusb_get_max_alt_packet_size@16 = libusb_get_max_alt_packet_size
|
||||
libusb_get_max_iso_packet_size
|
||||
libusb_get_max_iso_packet_size@8 = libusb_get_max_iso_packet_size
|
||||
libusb_get_max_packet_size
|
||||
libusb_get_max_packet_size@8 = libusb_get_max_packet_size
|
||||
libusb_get_next_timeout
|
||||
libusb_get_next_timeout@8 = libusb_get_next_timeout
|
||||
libusb_get_parent
|
||||
libusb_get_parent@4 = libusb_get_parent
|
||||
libusb_get_platform_descriptor
|
||||
libusb_get_platform_descriptor@12 = libusb_get_platform_descriptor
|
||||
libusb_get_pollfds
|
||||
libusb_get_pollfds@4 = libusb_get_pollfds
|
||||
libusb_get_port_number
|
||||
libusb_get_port_number@4 = libusb_get_port_number
|
||||
libusb_get_port_numbers
|
||||
libusb_get_port_numbers@12 = libusb_get_port_numbers
|
||||
libusb_get_port_path
|
||||
libusb_get_port_path@16 = libusb_get_port_path
|
||||
libusb_get_ss_endpoint_companion_descriptor
|
||||
libusb_get_ss_endpoint_companion_descriptor@12 = libusb_get_ss_endpoint_companion_descriptor
|
||||
libusb_get_ss_usb_device_capability_descriptor
|
||||
libusb_get_ss_usb_device_capability_descriptor@12 = libusb_get_ss_usb_device_capability_descriptor
|
||||
libusb_get_ssplus_usb_device_capability_descriptor
|
||||
libusb_get_ssplus_usb_device_capability_descriptor@12 = libusb_get_ssplus_usb_device_capability_descriptor
|
||||
libusb_get_string_descriptor_ascii
|
||||
libusb_get_string_descriptor_ascii@16 = libusb_get_string_descriptor_ascii
|
||||
libusb_get_usb_2_0_extension_descriptor
|
||||
libusb_get_usb_2_0_extension_descriptor@12 = libusb_get_usb_2_0_extension_descriptor
|
||||
libusb_get_version
|
||||
libusb_get_version@0 = libusb_get_version
|
||||
libusb_handle_events
|
||||
libusb_handle_events@4 = libusb_handle_events
|
||||
libusb_handle_events_completed
|
||||
libusb_handle_events_completed@8 = libusb_handle_events_completed
|
||||
libusb_handle_events_locked
|
||||
libusb_handle_events_locked@8 = libusb_handle_events_locked
|
||||
libusb_handle_events_timeout
|
||||
libusb_handle_events_timeout@8 = libusb_handle_events_timeout
|
||||
libusb_handle_events_timeout_completed
|
||||
libusb_handle_events_timeout_completed@12 = libusb_handle_events_timeout_completed
|
||||
libusb_has_capability
|
||||
libusb_has_capability@4 = libusb_has_capability
|
||||
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@36 = libusb_hotplug_register_callback
|
||||
libusb_init
|
||||
libusb_init@4 = libusb_init
|
||||
libusb_init_context
|
||||
libusb_init_context@12 = libusb_init_context
|
||||
libusb_interrupt_event_handler
|
||||
libusb_interrupt_event_handler@4 = libusb_interrupt_event_handler
|
||||
libusb_interrupt_transfer
|
||||
libusb_interrupt_transfer@24 = libusb_interrupt_transfer
|
||||
libusb_kernel_driver_active
|
||||
libusb_kernel_driver_active@8 = libusb_kernel_driver_active
|
||||
libusb_lock_event_waiters
|
||||
libusb_lock_event_waiters@4 = libusb_lock_event_waiters
|
||||
libusb_lock_events
|
||||
libusb_lock_events@4 = libusb_lock_events
|
||||
libusb_open
|
||||
libusb_open@8 = libusb_open
|
||||
libusb_open_device_with_vid_pid
|
||||
libusb_open_device_with_vid_pid@12 = libusb_open_device_with_vid_pid
|
||||
libusb_pollfds_handle_timeouts
|
||||
libusb_pollfds_handle_timeouts@4 = libusb_pollfds_handle_timeouts
|
||||
libusb_ref_device
|
||||
libusb_ref_device@4 = libusb_ref_device
|
||||
libusb_release_interface
|
||||
libusb_release_interface@8 = libusb_release_interface
|
||||
libusb_reset_device
|
||||
libusb_reset_device@4 = libusb_reset_device
|
||||
libusb_set_auto_detach_kernel_driver
|
||||
libusb_set_auto_detach_kernel_driver@8 = libusb_set_auto_detach_kernel_driver
|
||||
libusb_set_configuration
|
||||
libusb_set_configuration@8 = libusb_set_configuration
|
||||
libusb_set_debug
|
||||
libusb_set_debug@8 = libusb_set_debug
|
||||
libusb_set_interface_alt_setting
|
||||
libusb_set_interface_alt_setting@12 = libusb_set_interface_alt_setting
|
||||
libusb_set_log_cb
|
||||
libusb_set_log_cb@12 = libusb_set_log_cb
|
||||
libusb_set_option
|
||||
libusb_set_pollfd_notifiers
|
||||
libusb_set_pollfd_notifiers@16 = libusb_set_pollfd_notifiers
|
||||
libusb_setlocale
|
||||
libusb_setlocale@4 = libusb_setlocale
|
||||
libusb_strerror
|
||||
libusb_strerror@4 = libusb_strerror
|
||||
libusb_submit_transfer
|
||||
libusb_submit_transfer@4 = libusb_submit_transfer
|
||||
libusb_transfer_get_stream_id
|
||||
libusb_transfer_get_stream_id@4 = libusb_transfer_get_stream_id
|
||||
libusb_transfer_set_stream_id
|
||||
libusb_transfer_set_stream_id@8 = libusb_transfer_set_stream_id
|
||||
libusb_try_lock_events
|
||||
libusb_try_lock_events@4 = libusb_try_lock_events
|
||||
libusb_unlock_event_waiters
|
||||
libusb_unlock_event_waiters@4 = libusb_unlock_event_waiters
|
||||
libusb_unlock_events
|
||||
libusb_unlock_events@4 = libusb_unlock_events
|
||||
libusb_unref_device
|
||||
libusb_unref_device@4 = libusb_unref_device
|
||||
libusb_wait_for_event
|
||||
libusb_wait_for_event@8 = libusb_wait_for_event
|
||||
libusb_wrap_sys_device
|
||||
libusb_wrap_sys_device@12 = libusb_wrap_sys_device
|
||||
53
lib/libusb/libusb/libusb-1.0.rc
Normal file
53
lib/libusb/libusb/libusb-1.0.rc
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* For Windows: input this file to the Resource Compiler to produce a binary
|
||||
* .res file. This is then embedded in the resultant library (like any other
|
||||
* compilation object).
|
||||
* The information can then be queried using standard APIs and can also be
|
||||
* viewed with utilities such as Windows Explorer.
|
||||
*/
|
||||
#include "winresrc.h"
|
||||
|
||||
#include "version.h"
|
||||
#ifndef LIBUSB_VERSIONSTRING
|
||||
#define LU_STR(s) #s
|
||||
#define LU_XSTR(s) LU_STR(s)
|
||||
#define LIBUSB_VERSIONSTRING \
|
||||
LU_XSTR(LIBUSB_MAJOR) "." LU_XSTR(LIBUSB_MINOR) "." \
|
||||
LU_XSTR(LIBUSB_MICRO) "." LU_XSTR(LIBUSB_NANO) LIBUSB_RC "\0"
|
||||
#endif
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION LIBUSB_MAJOR,LIBUSB_MINOR,LIBUSB_MICRO,LIBUSB_NANO
|
||||
PRODUCTVERSION LIBUSB_MAJOR,LIBUSB_MINOR,LIBUSB_MICRO,LIBUSB_NANO
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x40004L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "libusb.info\0"
|
||||
VALUE "FileDescription", "C library for writing portable USB drivers in userspace\0"
|
||||
VALUE "FileVersion", LIBUSB_VERSIONSTRING
|
||||
VALUE "InternalName", "libusb\0"
|
||||
VALUE "LegalCopyright", "See individual source files, GNU LGPL v2.1 or later.\0"
|
||||
VALUE "LegalTrademarks", "http://www.gnu.org/licenses/lgpl-2.1.html\0"
|
||||
VALUE "OriginalFilename", "libusb-1.0.dll\0"
|
||||
VALUE "PrivateBuild", "\0"
|
||||
VALUE "ProductName", "libusb-1.0\0"
|
||||
VALUE "ProductVersion", LIBUSB_VERSIONSTRING
|
||||
VALUE "SpecialBuild", "\0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
2419
lib/libusb/libusb/libusb.h
Normal file
2419
lib/libusb/libusb/libusb.h
Normal file
File diff suppressed because it is too large
Load Diff
1535
lib/libusb/libusb/libusbi.h
Normal file
1535
lib/libusb/libusb/libusbi.h
Normal file
File diff suppressed because it is too large
Load Diff
2978
lib/libusb/libusb/os/darwin_usb.c
Normal file
2978
lib/libusb/libusb/os/darwin_usb.c
Normal file
File diff suppressed because it is too large
Load Diff
156
lib/libusb/libusb/os/darwin_usb.h
Normal file
156
lib/libusb/libusb/os/darwin_usb.h
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* darwin backend for libusb 1.0
|
||||
* Copyright © 2008-2023 Nathan Hjelm <hjelmn@users.sourceforge.net>
|
||||
* Copyright © 2019-2023 Google LLC. All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if !defined(LIBUSB_DARWIN_H)
|
||||
#define LIBUSB_DARWIN_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "libusbi.h"
|
||||
|
||||
#include <IOKit/IOTypes.h>
|
||||
#include <IOKit/IOCFBundle.h>
|
||||
#include <IOKit/usb/IOUSBLib.h>
|
||||
#include <IOKit/IOCFPlugIn.h>
|
||||
|
||||
#if defined(HAVE_IOKIT_USB_IOUSBHOSTFAMILYDEFINITIONS_H)
|
||||
#include <IOKit/usb/IOUSBHostFamilyDefinitions.h>
|
||||
#endif
|
||||
|
||||
/* IOUSBInterfaceInferface */
|
||||
|
||||
#if defined(kIOUSBInterfaceInterfaceID800)
|
||||
#define MAX_INTERFACE_VERSION 800
|
||||
#elif defined(kIOUSBInterfaceInterfaceID700)
|
||||
#define MAX_INTERFACE_VERSION 700
|
||||
#elif defined(kIOUSBInterfaceInterfaceID650)
|
||||
#define MAX_INTERFACE_VERSION 650
|
||||
#elif defined(kIOUSBInterfaceInterfaceID550)
|
||||
#define MAX_INTERFACE_VERSION 550
|
||||
#elif defined(kIOUSBInterfaceInterfaceID245)
|
||||
#define MAX_INTERFACE_VERSION 245
|
||||
#else
|
||||
#define MAX_INTERFACE_VERSION 220
|
||||
#endif
|
||||
|
||||
/* set to the minimum version and casted up as needed. */
|
||||
typedef IOUSBInterfaceInterface220 **usb_interface_t;
|
||||
|
||||
#define IOINTERFACE0(darwin_interface, version) ((IOUSBInterfaceInterface ## version **) (darwin_interface)->interface)
|
||||
#define IOINTERFACE_V(darwin_interface, version) IOINTERFACE0(darwin_interface, version)
|
||||
#define IOINTERFACE(darwin_interface) ((darwin_interface)->interface)
|
||||
|
||||
/* IOUSBDeviceInterface */
|
||||
|
||||
#if defined(kIOUSBDeviceInterfaceID650)
|
||||
#define MAX_DEVICE_VERSION 650
|
||||
#elif defined(kIOUSBDeviceInterfaceID500)
|
||||
#define MAX_DEVICE_VERSION 500
|
||||
#elif defined(kIOUSBDeviceInterfaceID320)
|
||||
#define MAX_DEVICE_VERSION 320
|
||||
#elif defined(kIOUSBDeviceInterfaceID300)
|
||||
#define MAX_DEVICE_VERSION 300
|
||||
#elif defined(kIOUSBDeviceInterfaceID245)
|
||||
#define MAX_DEVICE_VERSION 245
|
||||
#else
|
||||
#define MAX_DEVICE_VERSION 197
|
||||
#endif
|
||||
|
||||
/* set to the minimum version and casted up as needed */
|
||||
typedef IOUSBDeviceInterface197 **usb_device_t;
|
||||
|
||||
#define IODEVICE0(darwin_device, version) ((IOUSBDeviceInterface ## version **)(darwin_device))
|
||||
#define IODEVICE_V(darwin_device, version) IODEVICE0(darwin_device, version)
|
||||
|
||||
#if !defined(kIOUSBHostInterfaceClassName)
|
||||
#define kIOUSBHostInterfaceClassName "IOUSBHostInterface"
|
||||
#endif
|
||||
|
||||
#if !defined(kUSBHostMatchingPropertyInterfaceNumber)
|
||||
#define kUSBHostMatchingPropertyInterfaceNumber "bInterfaceNumber"
|
||||
#endif
|
||||
|
||||
#if !defined(IO_OBJECT_NULL)
|
||||
#define IO_OBJECT_NULL ((io_object_t) 0)
|
||||
#endif
|
||||
|
||||
/* returns the current macOS version in a format similar to the
|
||||
* MAC_OS_X_VERSION_MIN_REQUIRED macro.
|
||||
* Examples:
|
||||
* 10.1.5 -> 100105
|
||||
* 13.3.0 -> 130300
|
||||
*/
|
||||
uint32_t get_running_version(void);
|
||||
|
||||
typedef IOCFPlugInInterface *io_cf_plugin_ref_t;
|
||||
typedef IONotificationPortRef io_notification_port_t;
|
||||
|
||||
/* private structures */
|
||||
struct darwin_cached_device {
|
||||
struct list_head list;
|
||||
IOUSBDeviceDescriptor dev_descriptor;
|
||||
UInt32 location;
|
||||
UInt64 parent_session;
|
||||
UInt64 session;
|
||||
USBDeviceAddress address;
|
||||
char sys_path[21];
|
||||
usb_device_t device;
|
||||
io_service_t service;
|
||||
int open_count;
|
||||
UInt8 first_config, active_config, port;
|
||||
int can_enumerate;
|
||||
int refcount;
|
||||
bool in_reenumerate;
|
||||
int capture_count;
|
||||
};
|
||||
|
||||
struct darwin_device_priv {
|
||||
struct darwin_cached_device *dev;
|
||||
};
|
||||
|
||||
struct darwin_device_handle_priv {
|
||||
bool is_open;
|
||||
CFRunLoopSourceRef cfSource;
|
||||
|
||||
struct darwin_interface {
|
||||
usb_interface_t interface;
|
||||
uint8_t num_endpoints;
|
||||
CFRunLoopSourceRef cfSource;
|
||||
uint64_t frames[256];
|
||||
uint8_t endpoint_addrs[USB_MAXENDPOINTS];
|
||||
} interfaces[USB_MAXINTERFACES];
|
||||
};
|
||||
|
||||
struct darwin_transfer_priv {
|
||||
/* Isoc */
|
||||
IOUSBIsocFrame *isoc_framelist;
|
||||
int num_iso_packets;
|
||||
|
||||
/* Control */
|
||||
IOUSBDevRequestTO req;
|
||||
|
||||
/* Bulk */
|
||||
|
||||
/* Completion status */
|
||||
IOReturn result;
|
||||
UInt32 size;
|
||||
};
|
||||
|
||||
#endif
|
||||
875
lib/libusb/libusb/os/emscripten_webusb.cpp
Normal file
875
lib/libusb/libusb/os/emscripten_webusb.cpp
Normal file
@@ -0,0 +1,875 @@
|
||||
/*
|
||||
* Copyright © 2021 Google LLC
|
||||
* Copyright © 2023 Ingvar Stepanyan <me@rreverser.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
|
||||
*
|
||||
* Authors:
|
||||
* Ingvar Stepanyan <me@rreverser.com>
|
||||
*/
|
||||
|
||||
#include <emscripten/version.h>
|
||||
|
||||
static_assert((__EMSCRIPTEN_major__ * 100 * 100 + __EMSCRIPTEN_minor__ * 100 +
|
||||
__EMSCRIPTEN_tiny__) >= 30148,
|
||||
"Emscripten 3.1.48 or newer is required.");
|
||||
|
||||
#include <assert.h>
|
||||
#include <emscripten.h>
|
||||
#include <emscripten/val.h>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "libusbi.h"
|
||||
|
||||
using namespace emscripten;
|
||||
|
||||
#ifdef _REENTRANT
|
||||
#include <emscripten/proxying.h>
|
||||
#include <emscripten/threading.h>
|
||||
#include <pthread.h>
|
||||
|
||||
static ProxyingQueue queue;
|
||||
#endif
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||
#pragma clang diagnostic ignored "-Wunused-parameter"
|
||||
#pragma clang diagnostic ignored "-Wshadow"
|
||||
|
||||
namespace {
|
||||
|
||||
// clang-format off
|
||||
EM_JS(EM_VAL, usbi_em_promise_catch, (EM_VAL handle), {
|
||||
let promise = Emval.toValue(handle);
|
||||
promise = promise.then(
|
||||
value => ({error : 0, value}),
|
||||
error => {
|
||||
console.error(error);
|
||||
let errorCode = -99; // LIBUSB_ERROR_OTHER
|
||||
if (error instanceof DOMException) {
|
||||
const ERROR_CODES = {
|
||||
// LIBUSB_ERROR_IO
|
||||
NetworkError : -1,
|
||||
// LIBUSB_ERROR_INVALID_PARAM
|
||||
DataError : -2,
|
||||
TypeMismatchError : -2,
|
||||
IndexSizeError : -2,
|
||||
// LIBUSB_ERROR_ACCESS
|
||||
SecurityError : -3,
|
||||
// LIBUSB_ERROR_NOT_FOUND
|
||||
NotFoundError : -5,
|
||||
// LIBUSB_ERROR_BUSY
|
||||
InvalidStateError : -6,
|
||||
// LIBUSB_ERROR_TIMEOUT
|
||||
TimeoutError : -7,
|
||||
// LIBUSB_ERROR_INTERRUPTED
|
||||
AbortError : -10,
|
||||
// LIBUSB_ERROR_NOT_SUPPORTED
|
||||
NotSupportedError : -12,
|
||||
};
|
||||
errorCode = ERROR_CODES[error.name] ?? errorCode;
|
||||
} else if (error instanceof RangeError || error instanceof TypeError) {
|
||||
errorCode = -2; // LIBUSB_ERROR_INVALID_PARAM
|
||||
}
|
||||
return {error: errorCode, value: undefined};
|
||||
}
|
||||
);
|
||||
return Emval.toHandle(promise);
|
||||
});
|
||||
|
||||
EM_JS(void, usbi_em_copy_from_dataview, (void* dst, EM_VAL src), {
|
||||
src = Emval.toValue(src);
|
||||
src = new Uint8Array(src.buffer, src.byteOffset, src.byteLength);
|
||||
HEAPU8.set(src, dst);
|
||||
});
|
||||
|
||||
// Our implementation proxies operations from multiple threads to the same
|
||||
// underlying USBDevice on the main thread. This can lead to issues when
|
||||
// multiple threads try to open/close the same device at the same time.
|
||||
//
|
||||
// First, since open/close operations are asynchronous in WebUSB, we can end up
|
||||
// with multiple open/close operations in flight at the same time, which can
|
||||
// lead to unpredictable outcome (e.g. device got closed but opening succeeded
|
||||
// right before that).
|
||||
//
|
||||
// Second, since multiple threads are allowed to have their own handles to the
|
||||
// same device, we need to keep track of number of open handles and close the
|
||||
// device only when the last handle is closed.
|
||||
//
|
||||
// We fix both of these issues by using a shared promise chain that executes
|
||||
// open and close operations sequentially and keeps track of the reference count
|
||||
// in each promise's result. This way, we can ensure that only one open/close
|
||||
// operation is in flight at any given time. Note that we don't need to worry
|
||||
// about all other operations because they're preconditioned on the device being
|
||||
// open and having at least 1 reference anyway.
|
||||
EM_JS(EM_VAL, usbi_em_device_safe_open_close, (EM_VAL device, bool open), {
|
||||
device = Emval.toValue(device);
|
||||
const symbol = Symbol.for('libusb.open_close_chain');
|
||||
let promiseChain = device[symbol] ?? Promise.resolve(0);
|
||||
device[symbol] = promiseChain = promiseChain.then(async refCount => {
|
||||
if (open) {
|
||||
if (!refCount++) {
|
||||
await device.open();
|
||||
}
|
||||
} else {
|
||||
if (!--refCount) {
|
||||
await device.close();
|
||||
}
|
||||
}
|
||||
return refCount;
|
||||
});
|
||||
return Emval.toHandle(promiseChain);
|
||||
});
|
||||
// clang-format on
|
||||
|
||||
libusb_transfer_status getTransferStatus(const val& transfer_result) {
|
||||
auto status = transfer_result["status"].as<std::string>();
|
||||
if (status == "ok") {
|
||||
return LIBUSB_TRANSFER_COMPLETED;
|
||||
} else if (status == "stall") {
|
||||
return LIBUSB_TRANSFER_STALL;
|
||||
} else if (status == "babble") {
|
||||
return LIBUSB_TRANSFER_OVERFLOW;
|
||||
} else {
|
||||
return LIBUSB_TRANSFER_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// Note: this assumes that `dst` is valid for at least `src.byteLength` bytes.
|
||||
// This is true for all results returned from WebUSB as we pass max length to
|
||||
// the transfer APIs.
|
||||
void copyFromDataView(void* dst, const val& src) {
|
||||
usbi_em_copy_from_dataview(dst, src.as_handle());
|
||||
}
|
||||
|
||||
auto getUnsharedMemoryView(void* src, size_t len) {
|
||||
auto view = typed_memory_view(len, (uint8_t*)src);
|
||||
#ifdef _REENTRANT
|
||||
// Unfortunately, TypedArrays backed by SharedArrayBuffers are not accepted
|
||||
// by most Web APIs, trading off guaranteed thread-safety for performance
|
||||
// loss. The usual workaround is to copy them into a new TypedArray, which
|
||||
// is what we do here via the `.slice()` method.
|
||||
return val(view).call<val>("slice");
|
||||
#else
|
||||
// Non-threaded builds can avoid the copy penalty.
|
||||
return view;
|
||||
#endif
|
||||
}
|
||||
|
||||
// A helper that proxies a function call to the main thread if not already
|
||||
// there. This is a wrapper around Emscripten's raw proxying API with couple of
|
||||
// high-level improvements, namely support for destroying lambda on the target
|
||||
// thread as well as custom return types.
|
||||
template <typename Func>
|
||||
auto runOnMain(Func&& func) {
|
||||
#ifdef _REENTRANT
|
||||
if (!emscripten_is_main_runtime_thread()) {
|
||||
if constexpr (std::is_same_v<std::invoke_result_t<Func>, void>) {
|
||||
bool proxied =
|
||||
queue.proxySync(emscripten_main_runtime_thread_id(), [&func] {
|
||||
// Capture func by reference and move into a local variable
|
||||
// to render the captured func inert on the first (and only)
|
||||
// call. This way it can be safely destructed on the main
|
||||
// thread instead of the current one when this call
|
||||
// finishes. TODO: remove this when
|
||||
// https://github.com/emscripten-core/emscripten/issues/20610
|
||||
// is fixed.
|
||||
auto func_ = std::move(func);
|
||||
func_();
|
||||
});
|
||||
assert(proxied);
|
||||
return;
|
||||
} else {
|
||||
// A storage for the result of the function call.
|
||||
// TODO: remove when
|
||||
// https://github.com/emscripten-core/emscripten/issues/20611 is
|
||||
// implemented.
|
||||
std::optional<std::invoke_result_t<Func>> result;
|
||||
runOnMain(
|
||||
[&result, func = std::move(func)] { result.emplace(func()); });
|
||||
return std::move(result.value());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return func();
|
||||
}
|
||||
|
||||
// C++ struct representation for `{value, error}` object used by `CaughtPromise`
|
||||
// below.
|
||||
struct PromiseResult {
|
||||
int error;
|
||||
val value;
|
||||
|
||||
PromiseResult() = delete;
|
||||
PromiseResult(PromiseResult&&) = default;
|
||||
|
||||
PromiseResult(val&& result)
|
||||
: error(result["error"].as<int>()), value(result["value"]) {}
|
||||
|
||||
~PromiseResult() {
|
||||
// make sure value is freed on the thread it exists on
|
||||
runOnMain([value = std::move(value)] {});
|
||||
}
|
||||
};
|
||||
|
||||
struct CaughtPromise : val {
|
||||
CaughtPromise(val&& promise)
|
||||
: val(wrapPromiseWithCatch(std::move(promise))) {}
|
||||
|
||||
using AwaitResult = PromiseResult;
|
||||
|
||||
private:
|
||||
|
||||
// Wrap promise with conversion from some value T to `{value: T, error:
|
||||
// number}`.
|
||||
static val wrapPromiseWithCatch(val&& promise) {
|
||||
auto handle = promise.as_handle();
|
||||
handle = usbi_em_promise_catch(handle);
|
||||
return val::take_ownership(handle);
|
||||
}
|
||||
};
|
||||
|
||||
#define co_await_try(promise) \
|
||||
({ \
|
||||
PromiseResult result = co_await CaughtPromise(promise); \
|
||||
if (result.error) { \
|
||||
co_return result.error; \
|
||||
} \
|
||||
std::move(result.value); \
|
||||
})
|
||||
|
||||
// A helper that runs an asynchronous callback when the promise is resolved.
|
||||
template <typename Promise, typename OnResult>
|
||||
val promiseThen(Promise&& promise, OnResult&& onResult) {
|
||||
// Save captures from the callback while we can, or they'll be destructed.
|
||||
// https://devblogs.microsoft.com/oldnewthing/20211103-00/?p=105870
|
||||
auto onResult_ = std::move(onResult);
|
||||
onResult_(co_await promise);
|
||||
co_return val::undefined();
|
||||
}
|
||||
|
||||
// A helper that runs an asynchronous function on the main thread and blocks the
|
||||
// current thread until the promise is resolved (via Asyncify "blocking" if
|
||||
// already on the main thread or regular blocking otherwise).
|
||||
template <typename Func>
|
||||
static std::invoke_result_t<Func>::AwaitResult awaitOnMain(Func&& func) {
|
||||
#ifdef _REENTRANT
|
||||
if (!emscripten_is_main_runtime_thread()) {
|
||||
// If we're on a different thread, we can't use main thread's Asyncify
|
||||
// as multiple threads might be fighting for its state; instead, use
|
||||
// proxying to synchronously block the current thread until the promise
|
||||
// is complete.
|
||||
std::optional<typename std::invoke_result_t<Func>::AwaitResult> result;
|
||||
queue.proxySyncWithCtx(
|
||||
emscripten_main_runtime_thread_id(),
|
||||
[&result, &func](ProxyingQueue::ProxyingCtx ctx) {
|
||||
// Same as `func` in `runOnMain`, move to destruct on the first
|
||||
// call.
|
||||
auto func_ = std::move(func);
|
||||
promiseThen(
|
||||
func_(),
|
||||
[&result, ctx = std::move(ctx)](auto&& result_) mutable {
|
||||
result.emplace(std::move(result_));
|
||||
ctx.finish();
|
||||
});
|
||||
});
|
||||
return std::move(result.value());
|
||||
}
|
||||
#endif
|
||||
// If we're already on the main thread, use Asyncify to block until the
|
||||
// promise is resolved.
|
||||
return func().await();
|
||||
}
|
||||
|
||||
// A helper that makes a control transfer given a setup pointer (assumed to be
|
||||
// followed by data payload for out-transfers).
|
||||
val makeControlTransferPromise(const val& dev, libusb_control_setup* setup) {
|
||||
auto params = val::object();
|
||||
|
||||
const char* request_type = "unknown";
|
||||
// See LIBUSB_REQ_TYPE in windows_winusb.h (or docs for `bmRequestType`).
|
||||
switch (setup->bmRequestType & (0x03 << 5)) {
|
||||
case LIBUSB_REQUEST_TYPE_STANDARD:
|
||||
request_type = "standard";
|
||||
break;
|
||||
case LIBUSB_REQUEST_TYPE_CLASS:
|
||||
request_type = "class";
|
||||
break;
|
||||
case LIBUSB_REQUEST_TYPE_VENDOR:
|
||||
request_type = "vendor";
|
||||
break;
|
||||
}
|
||||
params.set("requestType", request_type);
|
||||
|
||||
const char* recipient = "other";
|
||||
switch (setup->bmRequestType & 0x0f) {
|
||||
case LIBUSB_RECIPIENT_DEVICE:
|
||||
recipient = "device";
|
||||
break;
|
||||
case LIBUSB_RECIPIENT_INTERFACE:
|
||||
recipient = "interface";
|
||||
break;
|
||||
case LIBUSB_RECIPIENT_ENDPOINT:
|
||||
recipient = "endpoint";
|
||||
break;
|
||||
}
|
||||
params.set("recipient", recipient);
|
||||
|
||||
params.set("request", setup->bRequest);
|
||||
params.set("value", setup->wValue);
|
||||
params.set("index", setup->wIndex);
|
||||
|
||||
if (setup->bmRequestType & LIBUSB_ENDPOINT_IN) {
|
||||
return dev.call<val>("controlTransferIn", params, setup->wLength);
|
||||
} else {
|
||||
return dev.call<val>("controlTransferOut", params,
|
||||
getUnsharedMemoryView(setup + 1, setup->wLength));
|
||||
}
|
||||
}
|
||||
|
||||
// Smart pointer for managing pointers to places allocated by libusb inside its
|
||||
// backend structures.
|
||||
template <typename T>
|
||||
struct ValPtr {
|
||||
template <typename... Args>
|
||||
void emplace(Args&&... args) {
|
||||
new (ptr) T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
const T& operator*() const { return *ptr; }
|
||||
T& operator*() { return *ptr; }
|
||||
|
||||
const T* operator->() const { return ptr; }
|
||||
T* operator->() { return ptr; }
|
||||
|
||||
void free() { ptr->~T(); }
|
||||
|
||||
T take() {
|
||||
auto value = std::move(*ptr);
|
||||
free();
|
||||
return value;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
ValPtr(void* ptr) : ptr(static_cast<T*>(ptr)) {}
|
||||
|
||||
private:
|
||||
|
||||
// Note: this is not a heap-allocated pointer, but a pointer to a part
|
||||
// of the backend structure allocated by libusb itself.
|
||||
T* ptr;
|
||||
};
|
||||
|
||||
struct CachedDevice;
|
||||
|
||||
struct WebUsbDevicePtr : ValPtr<CachedDevice> {
|
||||
public:
|
||||
|
||||
WebUsbDevicePtr(libusb_device* dev) : ValPtr(usbi_get_device_priv(dev)) {}
|
||||
WebUsbDevicePtr(libusb_device_handle* handle)
|
||||
: WebUsbDevicePtr(handle->dev) {}
|
||||
};
|
||||
|
||||
struct WebUsbTransferPtr : ValPtr<PromiseResult> {
|
||||
public:
|
||||
|
||||
WebUsbTransferPtr(usbi_transfer* itransfer)
|
||||
: ValPtr(usbi_get_transfer_priv(itransfer)) {}
|
||||
};
|
||||
|
||||
enum class OpenClose : bool {
|
||||
Open = true,
|
||||
Close = false,
|
||||
};
|
||||
|
||||
struct CachedDevice {
|
||||
CachedDevice() = delete;
|
||||
CachedDevice(CachedDevice&&) = delete;
|
||||
|
||||
// Fill in the device descriptor and configurations by reading them from the
|
||||
// WebUSB device.
|
||||
static val initFromDevice(val&& web_usb_dev, libusb_device* libusb_dev) {
|
||||
auto cachedDevicePtr = WebUsbDevicePtr(libusb_dev);
|
||||
cachedDevicePtr.emplace(std::move(web_usb_dev));
|
||||
bool must_close = false;
|
||||
val result = co_await cachedDevicePtr->initFromDeviceWithoutClosing(
|
||||
libusb_dev, must_close);
|
||||
if (must_close) {
|
||||
co_await_try(cachedDevicePtr->safeOpenCloseAssumingMainThread(
|
||||
OpenClose::Close));
|
||||
}
|
||||
co_return std::move(result);
|
||||
}
|
||||
|
||||
const val& getDeviceAssumingMainThread() const { return device; }
|
||||
|
||||
uint8_t getActiveConfigValue() const {
|
||||
return runOnMain([&] {
|
||||
auto web_usb_config = device["configuration"];
|
||||
return web_usb_config.isNull()
|
||||
? 0
|
||||
: web_usb_config["configurationValue"].as<uint8_t>();
|
||||
});
|
||||
}
|
||||
|
||||
usbi_configuration_descriptor* getConfigDescriptor(uint8_t config_id) {
|
||||
return config_id < configurations.size()
|
||||
? configurations[config_id].get()
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
usbi_configuration_descriptor* findConfigDescriptorByValue(
|
||||
uint8_t config_id) const {
|
||||
for (auto& config : configurations) {
|
||||
if (config->bConfigurationValue == config_id) {
|
||||
return config.get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int copyConfigDescriptor(const usbi_configuration_descriptor* config,
|
||||
void* buf,
|
||||
size_t buf_len) {
|
||||
auto len = std::min(buf_len, (size_t)config->wTotalLength);
|
||||
memcpy(buf, config, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
int awaitOnMain(const char* methodName, Args&&... args) const {
|
||||
return ::awaitOnMain([&] {
|
||||
return CaughtPromise(device.call<val>(
|
||||
methodName, std::forward<Args>(args)...));
|
||||
})
|
||||
.error;
|
||||
}
|
||||
|
||||
~CachedDevice() {
|
||||
runOnMain([device = std::move(device)] {});
|
||||
}
|
||||
|
||||
CaughtPromise safeOpenCloseAssumingMainThread(OpenClose open) {
|
||||
return val::take_ownership(usbi_em_device_safe_open_close(
|
||||
device.as_handle(), static_cast<bool>(open)));
|
||||
}
|
||||
|
||||
int safeOpenCloseOnMain(OpenClose open) {
|
||||
return ::awaitOnMain([this, open] {
|
||||
return safeOpenCloseAssumingMainThread(open);
|
||||
})
|
||||
.error;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
val device;
|
||||
std::vector<std::unique_ptr<usbi_configuration_descriptor>> configurations;
|
||||
|
||||
CaughtPromise requestDescriptor(libusb_descriptor_type desc_type,
|
||||
uint8_t desc_index,
|
||||
uint16_t max_length) const {
|
||||
libusb_control_setup setup = {
|
||||
.bmRequestType = LIBUSB_ENDPOINT_IN,
|
||||
.bRequest = LIBUSB_REQUEST_GET_DESCRIPTOR,
|
||||
.wValue = (uint16_t)((desc_type << 8) | desc_index),
|
||||
.wIndex = 0,
|
||||
.wLength = max_length,
|
||||
};
|
||||
return makeControlTransferPromise(device, &setup);
|
||||
}
|
||||
|
||||
// Implementation of the `CachedDevice::initFromDevice` above. This is a
|
||||
// separate function just because we need to close the device on exit if
|
||||
// we opened it successfully, and we can't use an async operation (`close`)
|
||||
// in RAII destructor.
|
||||
val initFromDeviceWithoutClosing(libusb_device* dev, bool& must_close) {
|
||||
co_await_try(safeOpenCloseAssumingMainThread(OpenClose::Open));
|
||||
|
||||
// Can't use RAII to close on exit as co_await is not permitted in
|
||||
// destructors (yet:
|
||||
// https://github.com/cplusplus/papers/issues/445), so use a good
|
||||
// old boolean + a wrapper instead.
|
||||
must_close = true;
|
||||
|
||||
{
|
||||
auto result = co_await_try(
|
||||
requestDescriptor(LIBUSB_DT_DEVICE, 0, LIBUSB_DT_DEVICE_SIZE));
|
||||
if (auto error = getTransferStatus(result)) {
|
||||
co_return error;
|
||||
}
|
||||
copyFromDataView(&dev->device_descriptor, result["data"]);
|
||||
}
|
||||
|
||||
// Infer the device speed (which is not yet provided by WebUSB) from
|
||||
// the descriptor.
|
||||
if (dev->device_descriptor.bMaxPacketSize0 ==
|
||||
/* actually means 2^9, only valid for superspeeds */ 9) {
|
||||
dev->speed = dev->device_descriptor.bcdUSB >= 0x0310
|
||||
? LIBUSB_SPEED_SUPER_PLUS
|
||||
: LIBUSB_SPEED_SUPER;
|
||||
} else if (dev->device_descriptor.bcdUSB >= 0x0200) {
|
||||
dev->speed = LIBUSB_SPEED_HIGH;
|
||||
} else if (dev->device_descriptor.bMaxPacketSize0 > 8) {
|
||||
dev->speed = LIBUSB_SPEED_FULL;
|
||||
} else {
|
||||
dev->speed = LIBUSB_SPEED_LOW;
|
||||
}
|
||||
|
||||
if (auto error = usbi_sanitize_device(dev)) {
|
||||
co_return error;
|
||||
}
|
||||
|
||||
auto configurations_len = dev->device_descriptor.bNumConfigurations;
|
||||
configurations.reserve(configurations_len);
|
||||
for (uint8_t j = 0; j < configurations_len; j++) {
|
||||
// Note: requesting more than (platform-specific limit) bytes
|
||||
// here will cause the transfer to fail, see
|
||||
// https://crbug.com/1489414. Use the most common limit of 4096
|
||||
// bytes for now.
|
||||
constexpr uint16_t MAX_CTRL_BUFFER_LENGTH = 4096;
|
||||
auto result = co_await_try(
|
||||
requestDescriptor(LIBUSB_DT_CONFIG, j, MAX_CTRL_BUFFER_LENGTH));
|
||||
if (auto error = getTransferStatus(result)) {
|
||||
co_return error;
|
||||
}
|
||||
auto configVal = result["data"];
|
||||
auto configLen = configVal["byteLength"].as<size_t>();
|
||||
auto& config = configurations.emplace_back(
|
||||
(usbi_configuration_descriptor*)::operator new(configLen));
|
||||
copyFromDataView(config.get(), configVal);
|
||||
}
|
||||
|
||||
co_return (int) LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
CachedDevice(val device) : device(std::move(device)) {}
|
||||
|
||||
friend struct ValPtr<CachedDevice>;
|
||||
};
|
||||
|
||||
unsigned long getDeviceSessionId(val& web_usb_device) {
|
||||
thread_local const val SessionIdSymbol =
|
||||
val::global("Symbol")(val("libusb.session_id"));
|
||||
|
||||
val session_id_val = web_usb_device[SessionIdSymbol];
|
||||
if (!session_id_val.isUndefined()) {
|
||||
return session_id_val.as<unsigned long>();
|
||||
}
|
||||
|
||||
// If the device doesn't have a session ID, it means we haven't seen
|
||||
// it before. Generate a new session ID for it. We can associate an
|
||||
// incrementing ID with the `USBDevice` object itself. It's
|
||||
// guaranteed to be alive and, thus, stable as long as the device is
|
||||
// connected, even between different libusb invocations. See
|
||||
// https://github.com/WICG/webusb/issues/241.
|
||||
|
||||
static unsigned long next_session_id = 0;
|
||||
|
||||
web_usb_device.set(SessionIdSymbol, next_session_id);
|
||||
return next_session_id++;
|
||||
}
|
||||
|
||||
val getDeviceList(libusb_context* ctx, discovered_devs** devs) {
|
||||
// Check if browser supports USB
|
||||
val navigator_usb = val::global("navigator")["usb"];
|
||||
if (navigator_usb == val::undefined()) {
|
||||
co_return (int) LIBUSB_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
// C++ equivalent of `await navigator.usb.getDevices()`. Note: at this point
|
||||
// we must already have some devices exposed - caller must have called
|
||||
// `await navigator.usb.requestDevice(...)` in response to user interaction
|
||||
// before going to LibUSB. Otherwise this list will be empty.
|
||||
auto web_usb_devices =
|
||||
co_await_try(navigator_usb.call<val>("getDevices"));
|
||||
for (auto&& web_usb_device : web_usb_devices) {
|
||||
auto session_id = getDeviceSessionId(web_usb_device);
|
||||
|
||||
auto dev = usbi_get_device_by_session_id(ctx, session_id);
|
||||
if (dev == NULL) {
|
||||
dev = usbi_alloc_device(ctx, session_id);
|
||||
if (dev == NULL) {
|
||||
usbi_err(ctx, "failed to allocate a new device structure");
|
||||
continue;
|
||||
}
|
||||
|
||||
auto statusVal = co_await CachedDevice::initFromDevice(
|
||||
std::move(web_usb_device), dev);
|
||||
if (auto error = statusVal.as<int>()) {
|
||||
usbi_err(ctx, "failed to read device information: %s",
|
||||
libusb_error_name(error));
|
||||
libusb_unref_device(dev);
|
||||
continue;
|
||||
}
|
||||
|
||||
// We don't have real buses in WebUSB, just pretend everything
|
||||
// is on bus 1.
|
||||
dev->bus_number = 1;
|
||||
// This can wrap around but it's the best approximation of a stable
|
||||
// device address and port number we can provide.
|
||||
dev->device_address = dev->port_number = (uint8_t)session_id;
|
||||
}
|
||||
*devs = discovered_devs_append(*devs, dev);
|
||||
libusb_unref_device(dev);
|
||||
}
|
||||
co_return (int) LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int em_get_device_list(libusb_context* ctx, discovered_devs** devs) {
|
||||
// No need to wrap into CaughtPromise as we catch all individual ops in the
|
||||
// inner implementation and return just the error code. We do need a custom
|
||||
// promise type to ensure conversion to int happens on the main thread
|
||||
// though.
|
||||
struct IntPromise : val {
|
||||
IntPromise(val&& promise) : val(std::move(promise)) {}
|
||||
|
||||
struct AwaitResult {
|
||||
int error;
|
||||
|
||||
AwaitResult(val&& result) : error(result.as<int>()) {}
|
||||
};
|
||||
};
|
||||
|
||||
return awaitOnMain(
|
||||
[ctx, devs] { return IntPromise(getDeviceList(ctx, devs)); })
|
||||
.error;
|
||||
}
|
||||
|
||||
int em_open(libusb_device_handle* handle) {
|
||||
return WebUsbDevicePtr(handle)->safeOpenCloseOnMain(OpenClose::Open);
|
||||
}
|
||||
|
||||
void em_close(libusb_device_handle* handle) {
|
||||
// LibUSB API doesn't allow us to handle an error here, but we still need to
|
||||
// wait for the promise to make sure that subsequent attempt to reopen the
|
||||
// same device doesn't fail with a "device busy" error.
|
||||
if (auto error =
|
||||
WebUsbDevicePtr(handle)->safeOpenCloseOnMain(OpenClose::Close)) {
|
||||
usbi_err(handle->dev->ctx, "failed to close device: %s",
|
||||
libusb_error_name(error));
|
||||
}
|
||||
}
|
||||
|
||||
int em_get_active_config_descriptor(libusb_device* dev, void* buf, size_t len) {
|
||||
auto& cached_device = *WebUsbDevicePtr(dev);
|
||||
auto config_value = cached_device.getActiveConfigValue();
|
||||
if (auto config = cached_device.findConfigDescriptorByValue(config_value)) {
|
||||
return cached_device.copyConfigDescriptor(config, buf, len);
|
||||
} else {
|
||||
return LIBUSB_ERROR_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
int em_get_config_descriptor(libusb_device* dev,
|
||||
uint8_t config_id,
|
||||
void* buf,
|
||||
size_t len) {
|
||||
auto& cached_device = *WebUsbDevicePtr(dev);
|
||||
if (auto config = cached_device.getConfigDescriptor(config_id)) {
|
||||
return cached_device.copyConfigDescriptor(config, buf, len);
|
||||
} else {
|
||||
return LIBUSB_ERROR_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
int em_get_configuration(libusb_device_handle* dev_handle,
|
||||
uint8_t* config_value) {
|
||||
*config_value = WebUsbDevicePtr(dev_handle)->getActiveConfigValue();
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int em_get_config_descriptor_by_value(libusb_device* dev,
|
||||
uint8_t config_value,
|
||||
void** buf) {
|
||||
auto& cached_device = *WebUsbDevicePtr(dev);
|
||||
if (auto config = cached_device.findConfigDescriptorByValue(config_value)) {
|
||||
*buf = config;
|
||||
return config->wTotalLength;
|
||||
} else {
|
||||
return LIBUSB_ERROR_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
int em_set_configuration(libusb_device_handle* dev_handle, int config) {
|
||||
return WebUsbDevicePtr(dev_handle)->awaitOnMain("setConfiguration", config);
|
||||
}
|
||||
|
||||
int em_claim_interface(libusb_device_handle* handle, uint8_t iface) {
|
||||
return WebUsbDevicePtr(handle)->awaitOnMain("claimInterface", iface);
|
||||
}
|
||||
|
||||
int em_release_interface(libusb_device_handle* handle, uint8_t iface) {
|
||||
return WebUsbDevicePtr(handle)->awaitOnMain("releaseInterface", iface);
|
||||
}
|
||||
|
||||
int em_set_interface_altsetting(libusb_device_handle* handle,
|
||||
uint8_t iface,
|
||||
uint8_t altsetting) {
|
||||
return WebUsbDevicePtr(handle)->awaitOnMain("selectAlternateInterface",
|
||||
iface, altsetting);
|
||||
}
|
||||
|
||||
int em_clear_halt(libusb_device_handle* handle, unsigned char endpoint) {
|
||||
std::string direction = endpoint & LIBUSB_ENDPOINT_IN ? "in" : "out";
|
||||
endpoint &= LIBUSB_ENDPOINT_ADDRESS_MASK;
|
||||
|
||||
return WebUsbDevicePtr(handle)->awaitOnMain("clearHalt", direction,
|
||||
endpoint);
|
||||
}
|
||||
|
||||
int em_reset_device(libusb_device_handle* handle) {
|
||||
return WebUsbDevicePtr(handle)->awaitOnMain("reset");
|
||||
}
|
||||
|
||||
void em_destroy_device(libusb_device* dev) {
|
||||
WebUsbDevicePtr(dev).free();
|
||||
}
|
||||
|
||||
int em_submit_transfer(usbi_transfer* itransfer) {
|
||||
return runOnMain([itransfer] {
|
||||
auto transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
||||
auto& web_usb_device = WebUsbDevicePtr(transfer->dev_handle)
|
||||
->getDeviceAssumingMainThread();
|
||||
val transfer_promise;
|
||||
switch (transfer->type) {
|
||||
case LIBUSB_TRANSFER_TYPE_CONTROL: {
|
||||
transfer_promise = makeControlTransferPromise(
|
||||
web_usb_device,
|
||||
libusb_control_transfer_get_setup(transfer));
|
||||
break;
|
||||
}
|
||||
case LIBUSB_TRANSFER_TYPE_BULK:
|
||||
case LIBUSB_TRANSFER_TYPE_INTERRUPT: {
|
||||
auto endpoint =
|
||||
transfer->endpoint & LIBUSB_ENDPOINT_ADDRESS_MASK;
|
||||
|
||||
if (IS_XFERIN(transfer)) {
|
||||
transfer_promise = web_usb_device.call<val>(
|
||||
"transferIn", endpoint, transfer->length);
|
||||
} else {
|
||||
auto data = getUnsharedMemoryView(transfer->buffer,
|
||||
transfer->length);
|
||||
transfer_promise =
|
||||
web_usb_device.call<val>("transferOut", endpoint, data);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
// TODO: add implementation for isochronous transfers too.
|
||||
default:
|
||||
return LIBUSB_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
// Not a coroutine because we don't want to block on this promise, just
|
||||
// schedule an asynchronous callback.
|
||||
promiseThen(CaughtPromise(std::move(transfer_promise)),
|
||||
[itransfer](auto&& result) {
|
||||
WebUsbTransferPtr(itransfer).emplace(std::move(result));
|
||||
usbi_signal_transfer_completion(itransfer);
|
||||
});
|
||||
return LIBUSB_SUCCESS;
|
||||
});
|
||||
}
|
||||
|
||||
void em_clear_transfer_priv(usbi_transfer* itransfer) {
|
||||
WebUsbTransferPtr(itransfer).free();
|
||||
}
|
||||
|
||||
int em_cancel_transfer(usbi_transfer* itransfer) {
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int em_handle_transfer_completion(usbi_transfer* itransfer) {
|
||||
libusb_transfer_status status = runOnMain([itransfer] {
|
||||
auto transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
||||
|
||||
// Take ownership of the transfer result, as `em_clear_transfer_priv` is
|
||||
// not called automatically for completed transfers and we must free it
|
||||
// to avoid leaks.
|
||||
|
||||
auto result = WebUsbTransferPtr(itransfer).take();
|
||||
|
||||
if (itransfer->state_flags & USBI_TRANSFER_CANCELLING) {
|
||||
return LIBUSB_TRANSFER_CANCELLED;
|
||||
}
|
||||
|
||||
if (result.error) {
|
||||
return LIBUSB_TRANSFER_ERROR;
|
||||
}
|
||||
|
||||
auto& value = result.value;
|
||||
|
||||
void* dataDest;
|
||||
unsigned char endpointDir;
|
||||
|
||||
if (transfer->type == LIBUSB_TRANSFER_TYPE_CONTROL) {
|
||||
dataDest = libusb_control_transfer_get_data(transfer);
|
||||
endpointDir =
|
||||
libusb_control_transfer_get_setup(transfer)->bmRequestType;
|
||||
} else {
|
||||
dataDest = transfer->buffer;
|
||||
endpointDir = transfer->endpoint;
|
||||
}
|
||||
|
||||
if (endpointDir & LIBUSB_ENDPOINT_IN) {
|
||||
auto data = value["data"];
|
||||
if (!data.isNull()) {
|
||||
itransfer->transferred = data["byteLength"].as<int>();
|
||||
copyFromDataView(dataDest, data);
|
||||
}
|
||||
} else {
|
||||
itransfer->transferred = value["bytesWritten"].as<int>();
|
||||
}
|
||||
|
||||
return getTransferStatus(value);
|
||||
});
|
||||
|
||||
// Invoke user's handlers outside of the main thread to reduce pressure.
|
||||
return status == LIBUSB_TRANSFER_CANCELLED
|
||||
? usbi_handle_transfer_cancellation(itransfer)
|
||||
: usbi_handle_transfer_completion(itransfer, status);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#pragma clang diagnostic ignored "-Wmissing-field-initializers"
|
||||
extern "C" const usbi_os_backend usbi_backend = {
|
||||
.name = "Emscripten + WebUSB backend",
|
||||
.caps = 0,
|
||||
.get_device_list = em_get_device_list,
|
||||
.open = em_open,
|
||||
.close = em_close,
|
||||
.get_active_config_descriptor = em_get_active_config_descriptor,
|
||||
.get_config_descriptor = em_get_config_descriptor,
|
||||
.get_config_descriptor_by_value = em_get_config_descriptor_by_value,
|
||||
.get_configuration = em_get_configuration,
|
||||
.set_configuration = em_set_configuration,
|
||||
.claim_interface = em_claim_interface,
|
||||
.release_interface = em_release_interface,
|
||||
.set_interface_altsetting = em_set_interface_altsetting,
|
||||
.clear_halt = em_clear_halt,
|
||||
.reset_device = em_reset_device,
|
||||
.destroy_device = em_destroy_device,
|
||||
.submit_transfer = em_submit_transfer,
|
||||
.cancel_transfer = em_cancel_transfer,
|
||||
.clear_transfer_priv = em_clear_transfer_priv,
|
||||
.handle_transfer_completion = em_handle_transfer_completion,
|
||||
.device_priv_size = sizeof(CachedDevice),
|
||||
.transfer_priv_size = sizeof(PromiseResult),
|
||||
};
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
340
lib/libusb/libusb/os/events_posix.c
Normal file
340
lib/libusb/libusb/os/events_posix.c
Normal file
@@ -0,0 +1,340 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
/* On Emscripten `pipe` does not conform to the spec and does not block
|
||||
* until events are available, which makes it unusable for event system
|
||||
* and often results in deadlocks when `pipe` is in a loop like it is
|
||||
* in libusb.
|
||||
*
|
||||
* Therefore use a custom event system based on browser event emitters. */
|
||||
#include <emscripten.h>
|
||||
#include <emscripten/atomic.h>
|
||||
#include <emscripten/threading.h>
|
||||
|
||||
EM_ASYNC_JS(void, em_libusb_wait_async, (const _Atomic int* ptr, int expected_value, int timeout), {
|
||||
await Atomics.waitAsync(HEAP32, ptr >> 2, expected_value, timeout).value;
|
||||
});
|
||||
|
||||
static void em_libusb_wait(const _Atomic int *ptr, int expected_value, int timeout)
|
||||
{
|
||||
if (emscripten_is_main_runtime_thread()) {
|
||||
em_libusb_wait_async(ptr, expected_value, timeout);
|
||||
} else {
|
||||
emscripten_atomic_wait_u32((int*)ptr, expected_value, 1000000LL * timeout);
|
||||
}
|
||||
}
|
||||
#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");
|
||||
#ifdef __EMSCRIPTEN__
|
||||
event->has_event = 1;
|
||||
emscripten_atomic_notify(&event->has_event, EMSCRIPTEN_NOTIFY_ALL_WAITERS);
|
||||
#endif
|
||||
}
|
||||
|
||||
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 __EMSCRIPTEN__
|
||||
event->has_event = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#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(ctx, "poll() %u fds with timeout in %dms", (unsigned int)nfds, timeout_ms);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
/* Emscripten's poll doesn't actually block, so we need to use an
|
||||
* out-of-band waiting signal. */
|
||||
em_libusb_wait(&ctx->event.has_event, 0, timeout_ms);
|
||||
/* Emscripten ignores timeout_ms, but set it to 0 for future-proofing
|
||||
* in case they ever implement real poll. */
|
||||
timeout_ms = 0;
|
||||
#endif
|
||||
num_ready = poll(fds, nfds, timeout_ms);
|
||||
usbi_dbg(ctx, "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(ctx, "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;
|
||||
}
|
||||
62
lib/libusb/libusb/os/events_posix.h
Normal file
62
lib/libusb/libusb/os/events_posix.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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];
|
||||
#ifdef __EMSCRIPTEN__
|
||||
_Atomic int has_event;
|
||||
#endif
|
||||
} 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
|
||||
214
lib/libusb/libusb/os/events_windows.c
Normal file
214
lib/libusb/libusb/os/events_windows.c
Normal 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(ctx, "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(ctx, "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;
|
||||
}
|
||||
46
lib/libusb/libusb/os/events_windows.h
Normal file
46
lib/libusb/libusb/os/events_windows.h
Normal 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
|
||||
372
lib/libusb/libusb/os/haiku_pollfs.cpp
Normal file
372
lib/libusb/libusb/os/haiku_pollfs.cpp
Normal file
@@ -0,0 +1,372 @@
|
||||
/*
|
||||
* Copyright 2007-2008, Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
*/
|
||||
|
||||
#include "haiku_usb.h"
|
||||
#include <cstdio>
|
||||
#include <Directory.h>
|
||||
#include <Entry.h>
|
||||
#include <Looper.h>
|
||||
#include <Messenger.h>
|
||||
#include <Node.h>
|
||||
#include <NodeMonitor.h>
|
||||
#include <Path.h>
|
||||
#include <cstring>
|
||||
|
||||
class WatchedEntry {
|
||||
public:
|
||||
WatchedEntry(BMessenger *, entry_ref *);
|
||||
~WatchedEntry();
|
||||
bool EntryCreated(entry_ref *ref);
|
||||
bool EntryRemoved(ino_t node);
|
||||
bool InitCheck();
|
||||
|
||||
private:
|
||||
BMessenger* fMessenger;
|
||||
node_ref fNode;
|
||||
bool fIsDirectory;
|
||||
USBDevice* fDevice;
|
||||
WatchedEntry* fEntries;
|
||||
WatchedEntry* fLink;
|
||||
bool fInitCheck;
|
||||
};
|
||||
|
||||
|
||||
class RosterLooper : public BLooper {
|
||||
public:
|
||||
RosterLooper(USBRoster *);
|
||||
void Stop();
|
||||
virtual void MessageReceived(BMessage *);
|
||||
bool InitCheck();
|
||||
|
||||
private:
|
||||
USBRoster* fRoster;
|
||||
WatchedEntry* fRoot;
|
||||
BMessenger* fMessenger;
|
||||
bool fInitCheck;
|
||||
};
|
||||
|
||||
|
||||
WatchedEntry::WatchedEntry(BMessenger *messenger, entry_ref *ref)
|
||||
: fMessenger(messenger),
|
||||
fIsDirectory(false),
|
||||
fDevice(NULL),
|
||||
fEntries(NULL),
|
||||
fLink(NULL),
|
||||
fInitCheck(false)
|
||||
{
|
||||
BEntry entry(ref);
|
||||
entry.GetNodeRef(&fNode);
|
||||
|
||||
BDirectory directory;
|
||||
if (entry.IsDirectory() && directory.SetTo(ref) >= B_OK) {
|
||||
fIsDirectory = true;
|
||||
|
||||
while (directory.GetNextEntry(&entry) >= B_OK) {
|
||||
if (entry.GetRef(ref) < B_OK)
|
||||
continue;
|
||||
|
||||
WatchedEntry *child = new(std::nothrow) WatchedEntry(fMessenger, ref);
|
||||
if (child == NULL)
|
||||
continue;
|
||||
if (child->InitCheck() == false) {
|
||||
delete child;
|
||||
continue;
|
||||
}
|
||||
|
||||
child->fLink = fEntries;
|
||||
fEntries = child;
|
||||
}
|
||||
|
||||
watch_node(&fNode, B_WATCH_DIRECTORY, *fMessenger);
|
||||
}
|
||||
else {
|
||||
if (strncmp(ref->name, "raw", 3) == 0)
|
||||
return;
|
||||
|
||||
BPath path, parent_path;
|
||||
entry.GetPath(&path);
|
||||
fDevice = new(std::nothrow) USBDevice(path.Path());
|
||||
if (fDevice != NULL && fDevice->InitCheck() == true) {
|
||||
// Add this new device to each active context's device list
|
||||
struct libusb_context *ctx;
|
||||
unsigned long session_id = (unsigned long)&fDevice;
|
||||
|
||||
usbi_mutex_lock(&active_contexts_lock);
|
||||
for_each_context(ctx) {
|
||||
struct libusb_device *dev = usbi_get_device_by_session_id(ctx, session_id);
|
||||
if (dev) {
|
||||
usbi_dbg(NULL, "using previously allocated device with location %lu", session_id);
|
||||
libusb_unref_device(dev);
|
||||
continue;
|
||||
}
|
||||
usbi_dbg(NULL, "allocating new device with location %lu", session_id);
|
||||
dev = usbi_alloc_device(ctx, session_id);
|
||||
if (!dev) {
|
||||
usbi_dbg(NULL, "device allocation failed");
|
||||
continue;
|
||||
}
|
||||
*((USBDevice **)usbi_get_device_priv(dev)) = fDevice;
|
||||
|
||||
// Calculate pseudo-device-address
|
||||
int addr, tmp;
|
||||
if (strcmp(path.Leaf(), "hub") == 0)
|
||||
tmp = 100; //Random Number
|
||||
else
|
||||
sscanf(path.Leaf(), "%d", &tmp);
|
||||
addr = tmp + 1;
|
||||
path.GetParent(&parent_path);
|
||||
while (strcmp(parent_path.Leaf(), "usb") != 0) {
|
||||
sscanf(parent_path.Leaf(), "%d", &tmp);
|
||||
addr += tmp + 1;
|
||||
parent_path.GetParent(&parent_path);
|
||||
}
|
||||
sscanf(path.Path(), "/dev/bus/usb/%hhu", &dev->bus_number);
|
||||
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) {
|
||||
usbi_dbg(NULL, "device sanitization failed");
|
||||
libusb_unref_device(dev);
|
||||
continue;
|
||||
}
|
||||
usbi_connect_device(dev);
|
||||
}
|
||||
usbi_mutex_unlock(&active_contexts_lock);
|
||||
}
|
||||
else if (fDevice) {
|
||||
delete fDevice;
|
||||
fDevice = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
fInitCheck = true;
|
||||
}
|
||||
|
||||
|
||||
WatchedEntry::~WatchedEntry()
|
||||
{
|
||||
if (fIsDirectory) {
|
||||
watch_node(&fNode, B_STOP_WATCHING, *fMessenger);
|
||||
|
||||
WatchedEntry *child = fEntries;
|
||||
while (child) {
|
||||
WatchedEntry *next = child->fLink;
|
||||
delete child;
|
||||
child = next;
|
||||
}
|
||||
}
|
||||
|
||||
if (fDevice) {
|
||||
// Remove this device from each active context's device list
|
||||
struct libusb_context *ctx;
|
||||
struct libusb_device *dev;
|
||||
unsigned long session_id = (unsigned long)&fDevice;
|
||||
|
||||
usbi_mutex_lock(&active_contexts_lock);
|
||||
for_each_context(ctx) {
|
||||
dev = usbi_get_device_by_session_id(ctx, session_id);
|
||||
if (dev != NULL) {
|
||||
usbi_disconnect_device(dev);
|
||||
libusb_unref_device(dev);
|
||||
} else {
|
||||
usbi_dbg(ctx, "device with location %lu not found", session_id);
|
||||
}
|
||||
}
|
||||
usbi_mutex_static_unlock(&active_contexts_lock);
|
||||
delete fDevice;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
WatchedEntry::EntryCreated(entry_ref *ref)
|
||||
{
|
||||
if (!fIsDirectory)
|
||||
return false;
|
||||
|
||||
if (ref->directory != fNode.node) {
|
||||
WatchedEntry *child = fEntries;
|
||||
while (child) {
|
||||
if (child->EntryCreated(ref))
|
||||
return true;
|
||||
child = child->fLink;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
WatchedEntry *child = new(std::nothrow) WatchedEntry(fMessenger, ref);
|
||||
if (child == NULL)
|
||||
return false;
|
||||
child->fLink = fEntries;
|
||||
fEntries = child;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
WatchedEntry::EntryRemoved(ino_t node)
|
||||
{
|
||||
if (!fIsDirectory)
|
||||
return false;
|
||||
|
||||
WatchedEntry *child = fEntries;
|
||||
WatchedEntry *lastChild = NULL;
|
||||
while (child) {
|
||||
if (child->fNode.node == node) {
|
||||
if (lastChild)
|
||||
lastChild->fLink = child->fLink;
|
||||
else
|
||||
fEntries = child->fLink;
|
||||
delete child;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (child->EntryRemoved(node))
|
||||
return true;
|
||||
|
||||
lastChild = child;
|
||||
child = child->fLink;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
WatchedEntry::InitCheck()
|
||||
{
|
||||
return fInitCheck;
|
||||
}
|
||||
|
||||
|
||||
RosterLooper::RosterLooper(USBRoster *roster)
|
||||
: BLooper("LibusbRoster Looper"),
|
||||
fRoster(roster),
|
||||
fRoot(NULL),
|
||||
fMessenger(NULL),
|
||||
fInitCheck(false)
|
||||
{
|
||||
BEntry entry("/dev/bus/usb");
|
||||
if (!entry.Exists()) {
|
||||
usbi_err(NULL, "usb_raw not published");
|
||||
return;
|
||||
}
|
||||
|
||||
Run();
|
||||
fMessenger = new(std::nothrow) BMessenger(this);
|
||||
if (fMessenger == NULL) {
|
||||
usbi_err(NULL, "error creating BMessenger object");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Lock()) {
|
||||
entry_ref ref;
|
||||
entry.GetRef(&ref);
|
||||
fRoot = new(std::nothrow) WatchedEntry(fMessenger, &ref);
|
||||
Unlock();
|
||||
if (fRoot == NULL)
|
||||
return;
|
||||
if (fRoot->InitCheck() == false) {
|
||||
delete fRoot;
|
||||
fRoot = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
fInitCheck = true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
RosterLooper::Stop()
|
||||
{
|
||||
Lock();
|
||||
delete fRoot;
|
||||
delete fMessenger;
|
||||
Quit();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
RosterLooper::MessageReceived(BMessage *message)
|
||||
{
|
||||
int32 opcode;
|
||||
if (message->FindInt32("opcode", &opcode) < B_OK)
|
||||
return;
|
||||
|
||||
switch (opcode) {
|
||||
case B_ENTRY_CREATED:
|
||||
{
|
||||
dev_t device;
|
||||
ino_t directory;
|
||||
const char *name;
|
||||
if (message->FindInt32("device", &device) < B_OK ||
|
||||
message->FindInt64("directory", &directory) < B_OK ||
|
||||
message->FindString("name", &name) < B_OK)
|
||||
break;
|
||||
|
||||
entry_ref ref(device, directory, name);
|
||||
fRoot->EntryCreated(&ref);
|
||||
break;
|
||||
}
|
||||
case B_ENTRY_REMOVED:
|
||||
{
|
||||
ino_t node;
|
||||
if (message->FindInt64("node", &node) < B_OK)
|
||||
break;
|
||||
fRoot->EntryRemoved(node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
RosterLooper::InitCheck()
|
||||
{
|
||||
return fInitCheck;
|
||||
}
|
||||
|
||||
|
||||
USBRoster::USBRoster()
|
||||
: fLooper(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
USBRoster::~USBRoster()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
USBRoster::Start()
|
||||
{
|
||||
if (fLooper == NULL) {
|
||||
fLooper = new(std::nothrow) RosterLooper(this);
|
||||
if (fLooper == NULL || ((RosterLooper *)fLooper)->InitCheck() == false) {
|
||||
if (fLooper)
|
||||
fLooper = NULL;
|
||||
return LIBUSB_ERROR_OTHER;
|
||||
}
|
||||
}
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
USBRoster::Stop()
|
||||
{
|
||||
if (fLooper) {
|
||||
((RosterLooper *)fLooper)->Stop();
|
||||
fLooper = NULL;
|
||||
}
|
||||
}
|
||||
113
lib/libusb/libusb/os/haiku_usb.h
Normal file
113
lib/libusb/libusb/os/haiku_usb.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Haiku Backend for libusb
|
||||
* Copyright © 2014 Akshay Jaggi <akshay1994.leo@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 <List.h>
|
||||
#include <Locker.h>
|
||||
#include <Autolock.h>
|
||||
#include <USBKit.h>
|
||||
#include <map>
|
||||
#include "libusbi.h"
|
||||
#include "haiku_usb_raw.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class USBDevice;
|
||||
class USBDeviceHandle;
|
||||
class USBTransfer;
|
||||
|
||||
class USBDevice {
|
||||
public:
|
||||
USBDevice(const char *);
|
||||
virtual ~USBDevice();
|
||||
const char* Location() const;
|
||||
uint8 CountConfigurations() const;
|
||||
const usb_device_descriptor* Descriptor() const;
|
||||
const usb_configuration_descriptor* ConfigurationDescriptor(uint8) const;
|
||||
const usb_configuration_descriptor* ActiveConfiguration() const;
|
||||
uint8 EndpointToIndex(uint8) const;
|
||||
uint8 EndpointToInterface(uint8) const;
|
||||
int ClaimInterface(uint8);
|
||||
int ReleaseInterface(uint8);
|
||||
int CheckInterfacesFree(uint8);
|
||||
void SetActiveConfiguration(uint8);
|
||||
uint8 ActiveConfigurationIndex() const;
|
||||
bool InitCheck();
|
||||
private:
|
||||
int Initialise();
|
||||
unsigned int fClaimedInterfaces; // Max Interfaces can be 32. Using a bitmask
|
||||
usb_device_descriptor fDeviceDescriptor;
|
||||
unsigned char** fConfigurationDescriptors;
|
||||
uint8 fActiveConfiguration;
|
||||
char* fPath;
|
||||
map<uint8,uint8> fConfigToIndex;
|
||||
map<uint8,uint8>* fEndpointToIndex;
|
||||
map<uint8,uint8>* fEndpointToInterface;
|
||||
bool fInitCheck;
|
||||
};
|
||||
|
||||
class USBDeviceHandle {
|
||||
public:
|
||||
USBDeviceHandle(USBDevice *dev);
|
||||
virtual ~USBDeviceHandle();
|
||||
int ClaimInterface(uint8);
|
||||
int ReleaseInterface(uint8);
|
||||
int SetConfiguration(uint8);
|
||||
int SetAltSetting(uint8, uint8);
|
||||
int ClearHalt(uint8);
|
||||
status_t SubmitTransfer(struct usbi_transfer *);
|
||||
status_t CancelTransfer(USBTransfer *);
|
||||
bool InitCheck();
|
||||
private:
|
||||
int fRawFD;
|
||||
static status_t TransfersThread(void *);
|
||||
void TransfersWorker();
|
||||
USBDevice* fUSBDevice;
|
||||
unsigned int fClaimedInterfaces;
|
||||
BList fTransfers;
|
||||
BLocker fTransfersLock;
|
||||
sem_id fTransfersSem;
|
||||
thread_id fTransfersThread;
|
||||
bool fInitCheck;
|
||||
};
|
||||
|
||||
class USBTransfer {
|
||||
public:
|
||||
USBTransfer(struct usbi_transfer *, USBDevice *);
|
||||
virtual ~USBTransfer();
|
||||
void Do(int);
|
||||
struct usbi_transfer* UsbiTransfer();
|
||||
void SetCancelled();
|
||||
bool IsCancelled();
|
||||
private:
|
||||
struct usbi_transfer* fUsbiTransfer;
|
||||
struct libusb_transfer* fLibusbTransfer;
|
||||
USBDevice* fUSBDevice;
|
||||
BLocker fStatusLock;
|
||||
bool fCancelled;
|
||||
};
|
||||
|
||||
class USBRoster {
|
||||
public:
|
||||
USBRoster();
|
||||
virtual ~USBRoster();
|
||||
int Start();
|
||||
void Stop();
|
||||
private:
|
||||
void* fLooper;
|
||||
};
|
||||
532
lib/libusb/libusb/os/haiku_usb_backend.cpp
Normal file
532
lib/libusb/libusb/os/haiku_usb_backend.cpp
Normal file
@@ -0,0 +1,532 @@
|
||||
/*
|
||||
* Haiku Backend for libusb
|
||||
* Copyright © 2014 Akshay Jaggi <akshay1994.leo@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 <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <new>
|
||||
#include <vector>
|
||||
|
||||
#include "haiku_usb.h"
|
||||
|
||||
static int _errno_to_libusb(int status)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
USBTransfer::USBTransfer(struct usbi_transfer *itransfer, USBDevice *device)
|
||||
{
|
||||
fUsbiTransfer = itransfer;
|
||||
fLibusbTransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
||||
fUSBDevice = device;
|
||||
fCancelled = false;
|
||||
}
|
||||
|
||||
USBTransfer::~USBTransfer()
|
||||
{
|
||||
}
|
||||
|
||||
struct usbi_transfer *
|
||||
USBTransfer::UsbiTransfer()
|
||||
{
|
||||
return fUsbiTransfer;
|
||||
}
|
||||
|
||||
void
|
||||
USBTransfer::SetCancelled()
|
||||
{
|
||||
fCancelled = true;
|
||||
}
|
||||
|
||||
bool
|
||||
USBTransfer::IsCancelled()
|
||||
{
|
||||
return fCancelled;
|
||||
}
|
||||
|
||||
void
|
||||
USBTransfer::Do(int fRawFD)
|
||||
{
|
||||
switch (fLibusbTransfer->type) {
|
||||
case LIBUSB_TRANSFER_TYPE_CONTROL:
|
||||
{
|
||||
struct libusb_control_setup *setup = (struct libusb_control_setup *)fLibusbTransfer->buffer;
|
||||
usb_raw_command command;
|
||||
command.control.request_type = setup->bmRequestType;
|
||||
command.control.request = setup->bRequest;
|
||||
command.control.value = setup->wValue;
|
||||
command.control.index = setup->wIndex;
|
||||
command.control.length = setup->wLength;
|
||||
command.control.data = fLibusbTransfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
|
||||
if (fCancelled)
|
||||
break;
|
||||
if (ioctl(fRawFD, B_USB_RAW_COMMAND_CONTROL_TRANSFER, &command, sizeof(command)) ||
|
||||
command.control.status != B_USB_RAW_STATUS_SUCCESS) {
|
||||
fUsbiTransfer->transferred = -1;
|
||||
usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed control transfer");
|
||||
break;
|
||||
}
|
||||
fUsbiTransfer->transferred = command.control.length;
|
||||
}
|
||||
break;
|
||||
case LIBUSB_TRANSFER_TYPE_BULK:
|
||||
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
|
||||
{
|
||||
usb_raw_command command;
|
||||
command.transfer.interface = fUSBDevice->EndpointToInterface(fLibusbTransfer->endpoint);
|
||||
command.transfer.endpoint = fUSBDevice->EndpointToIndex(fLibusbTransfer->endpoint);
|
||||
command.transfer.data = fLibusbTransfer->buffer;
|
||||
command.transfer.length = fLibusbTransfer->length;
|
||||
if (fCancelled)
|
||||
break;
|
||||
if (fLibusbTransfer->type == LIBUSB_TRANSFER_TYPE_BULK) {
|
||||
if (ioctl(fRawFD, B_USB_RAW_COMMAND_BULK_TRANSFER, &command, sizeof(command)) ||
|
||||
command.transfer.status != B_USB_RAW_STATUS_SUCCESS) {
|
||||
fUsbiTransfer->transferred = -1;
|
||||
usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed bulk transfer");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (ioctl(fRawFD, B_USB_RAW_COMMAND_INTERRUPT_TRANSFER, &command, sizeof(command)) ||
|
||||
command.transfer.status != B_USB_RAW_STATUS_SUCCESS) {
|
||||
fUsbiTransfer->transferred = -1;
|
||||
usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed interrupt transfer");
|
||||
break;
|
||||
}
|
||||
}
|
||||
fUsbiTransfer->transferred = command.transfer.length;
|
||||
}
|
||||
break;
|
||||
// IsochronousTransfers not tested
|
||||
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
|
||||
{
|
||||
usb_raw_command command;
|
||||
command.isochronous.interface = fUSBDevice->EndpointToInterface(fLibusbTransfer->endpoint);
|
||||
command.isochronous.endpoint = fUSBDevice->EndpointToIndex(fLibusbTransfer->endpoint);
|
||||
command.isochronous.data = fLibusbTransfer->buffer;
|
||||
command.isochronous.length = fLibusbTransfer->length;
|
||||
command.isochronous.packet_count = fLibusbTransfer->num_iso_packets;
|
||||
int i;
|
||||
usb_iso_packet_descriptor *packetDescriptors = new usb_iso_packet_descriptor[fLibusbTransfer->num_iso_packets];
|
||||
for (i = 0; i < fLibusbTransfer->num_iso_packets; i++) {
|
||||
if ((fLibusbTransfer->iso_packet_desc[i]).length > (unsigned int)INT16_MAX) {
|
||||
fUsbiTransfer->transferred = -1;
|
||||
usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed isochronous transfer");
|
||||
break;
|
||||
}
|
||||
packetDescriptors[i].request_length = (int16)(fLibusbTransfer->iso_packet_desc[i]).length;
|
||||
}
|
||||
if (i < fLibusbTransfer->num_iso_packets)
|
||||
break; // TODO Handle this error
|
||||
command.isochronous.packet_descriptors = packetDescriptors;
|
||||
if (fCancelled)
|
||||
break;
|
||||
if (ioctl(fRawFD, B_USB_RAW_COMMAND_ISOCHRONOUS_TRANSFER, &command, sizeof(command)) ||
|
||||
command.isochronous.status != B_USB_RAW_STATUS_SUCCESS) {
|
||||
fUsbiTransfer->transferred = -1;
|
||||
usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed isochronous transfer");
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < fLibusbTransfer->num_iso_packets; i++) {
|
||||
(fLibusbTransfer->iso_packet_desc[i]).actual_length = packetDescriptors[i].actual_length;
|
||||
switch (packetDescriptors[i].status) {
|
||||
case B_OK:
|
||||
(fLibusbTransfer->iso_packet_desc[i]).status = LIBUSB_TRANSFER_COMPLETED;
|
||||
break;
|
||||
default:
|
||||
(fLibusbTransfer->iso_packet_desc[i]).status = LIBUSB_TRANSFER_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete[] packetDescriptors;
|
||||
// Do we put the length of transfer here, for isochronous transfers?
|
||||
fUsbiTransfer->transferred = command.transfer.length;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
usbi_err(TRANSFER_CTX(fLibusbTransfer), "Unknown type of transfer");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
USBDeviceHandle::InitCheck()
|
||||
{
|
||||
return fInitCheck;
|
||||
}
|
||||
|
||||
status_t
|
||||
USBDeviceHandle::TransfersThread(void *self)
|
||||
{
|
||||
USBDeviceHandle *handle = (USBDeviceHandle *)self;
|
||||
handle->TransfersWorker();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
void
|
||||
USBDeviceHandle::TransfersWorker()
|
||||
{
|
||||
while (true) {
|
||||
status_t status = acquire_sem(fTransfersSem);
|
||||
if (status == B_BAD_SEM_ID)
|
||||
break;
|
||||
if (status == B_INTERRUPTED)
|
||||
continue;
|
||||
fTransfersLock.Lock();
|
||||
USBTransfer *fPendingTransfer = (USBTransfer *) fTransfers.RemoveItem((int32)0);
|
||||
fTransfersLock.Unlock();
|
||||
fPendingTransfer->Do(fRawFD);
|
||||
usbi_signal_transfer_completion(fPendingTransfer->UsbiTransfer());
|
||||
}
|
||||
}
|
||||
|
||||
status_t
|
||||
USBDeviceHandle::SubmitTransfer(struct usbi_transfer *itransfer)
|
||||
{
|
||||
USBTransfer *transfer = new USBTransfer(itransfer, fUSBDevice);
|
||||
*((USBTransfer **)usbi_get_transfer_priv(itransfer)) = transfer;
|
||||
BAutolock locker(fTransfersLock);
|
||||
fTransfers.AddItem(transfer);
|
||||
release_sem(fTransfersSem);
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
status_t
|
||||
USBDeviceHandle::CancelTransfer(USBTransfer *transfer)
|
||||
{
|
||||
transfer->SetCancelled();
|
||||
fTransfersLock.Lock();
|
||||
bool removed = fTransfers.RemoveItem(transfer);
|
||||
fTransfersLock.Unlock();
|
||||
if (removed)
|
||||
usbi_signal_transfer_completion(transfer->UsbiTransfer());
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
USBDeviceHandle::USBDeviceHandle(USBDevice *dev)
|
||||
:
|
||||
fUSBDevice(dev),
|
||||
fClaimedInterfaces(0),
|
||||
fTransfersThread(-1),
|
||||
fInitCheck(false)
|
||||
{
|
||||
fRawFD = open(dev->Location(), O_RDWR | O_CLOEXEC);
|
||||
if (fRawFD < 0) {
|
||||
usbi_err(NULL,"failed to open device");
|
||||
return;
|
||||
}
|
||||
fTransfersSem = create_sem(0, "Transfers Queue Sem");
|
||||
fTransfersThread = spawn_thread(TransfersThread, "Transfer Worker", B_NORMAL_PRIORITY, this);
|
||||
resume_thread(fTransfersThread);
|
||||
fInitCheck = true;
|
||||
}
|
||||
|
||||
USBDeviceHandle::~USBDeviceHandle()
|
||||
{
|
||||
if (fRawFD > 0)
|
||||
close(fRawFD);
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (fClaimedInterfaces & (1U << i))
|
||||
ReleaseInterface(i);
|
||||
}
|
||||
delete_sem(fTransfersSem);
|
||||
if (fTransfersThread > 0)
|
||||
wait_for_thread(fTransfersThread, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
USBDeviceHandle::ClaimInterface(uint8 inumber)
|
||||
{
|
||||
int status = fUSBDevice->ClaimInterface(inumber);
|
||||
if (status == LIBUSB_SUCCESS)
|
||||
fClaimedInterfaces |= (1U << inumber);
|
||||
return status;
|
||||
}
|
||||
|
||||
int
|
||||
USBDeviceHandle::ReleaseInterface(uint8 inumber)
|
||||
{
|
||||
fUSBDevice->ReleaseInterface(inumber);
|
||||
fClaimedInterfaces &= ~(1U << inumber);
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
USBDeviceHandle::SetConfiguration(uint8 config)
|
||||
{
|
||||
int config_index = fUSBDevice->CheckInterfacesFree(config);
|
||||
if (config_index == LIBUSB_ERROR_BUSY || config_index == LIBUSB_ERROR_NOT_FOUND)
|
||||
return config_index;
|
||||
usb_raw_command command;
|
||||
command.config.config_index = config_index;
|
||||
if (ioctl(fRawFD, B_USB_RAW_COMMAND_SET_CONFIGURATION, &command, sizeof(command)) ||
|
||||
command.config.status != B_USB_RAW_STATUS_SUCCESS) {
|
||||
return _errno_to_libusb(command.config.status);
|
||||
}
|
||||
fUSBDevice->SetActiveConfiguration((uint8)config_index);
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
USBDeviceHandle::SetAltSetting(uint8 inumber, uint8 alt)
|
||||
{
|
||||
usb_raw_command command;
|
||||
command.alternate.config_index = fUSBDevice->ActiveConfigurationIndex();
|
||||
command.alternate.interface_index = inumber;
|
||||
if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ACTIVE_ALT_INTERFACE_INDEX, &command, sizeof(command)) ||
|
||||
command.alternate.status != B_USB_RAW_STATUS_SUCCESS) {
|
||||
usbi_err(NULL, "Error retrieving active alternate interface");
|
||||
return _errno_to_libusb(command.alternate.status);
|
||||
}
|
||||
if (command.alternate.alternate_info == (uint32)alt) {
|
||||
usbi_dbg(NULL, "Setting alternate interface successful");
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
command.alternate.alternate_info = alt;
|
||||
if (ioctl(fRawFD, B_USB_RAW_COMMAND_SET_ALT_INTERFACE, &command, sizeof(command)) ||
|
||||
command.alternate.status != B_USB_RAW_STATUS_SUCCESS) { //IF IOCTL FAILS DEVICE DISCONNECTED PROBABLY
|
||||
usbi_err(NULL, "Error setting alternate interface");
|
||||
return _errno_to_libusb(command.alternate.status);
|
||||
}
|
||||
usbi_dbg(NULL, "Setting alternate interface successful");
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
USBDeviceHandle::ClearHalt(uint8 endpoint)
|
||||
{
|
||||
usb_raw_command command;
|
||||
command.control.request_type = USB_REQTYPE_ENDPOINT_OUT;
|
||||
command.control.request = USB_REQUEST_CLEAR_FEATURE;
|
||||
command.control.value = USB_FEATURE_ENDPOINT_HALT;
|
||||
command.control.index = endpoint;
|
||||
command.control.length = 0;
|
||||
|
||||
if (ioctl(fRawFD, B_USB_RAW_COMMAND_CONTROL_TRANSFER, &command, sizeof(command)) ||
|
||||
command.control.status != B_USB_RAW_STATUS_SUCCESS) {
|
||||
return _errno_to_libusb(command.control.status);
|
||||
}
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
USBDevice::USBDevice(const char *path)
|
||||
:
|
||||
fClaimedInterfaces(0),
|
||||
fConfigurationDescriptors(NULL),
|
||||
fActiveConfiguration(0), //0?
|
||||
fPath(NULL),
|
||||
fEndpointToIndex(NULL),
|
||||
fEndpointToInterface(NULL),
|
||||
fInitCheck(false)
|
||||
{
|
||||
fPath=strdup(path);
|
||||
Initialise();
|
||||
}
|
||||
|
||||
USBDevice::~USBDevice()
|
||||
{
|
||||
free(fPath);
|
||||
if (fConfigurationDescriptors) {
|
||||
for (uint8 i = 0; i < fDeviceDescriptor.num_configurations; i++) {
|
||||
if (fConfigurationDescriptors[i])
|
||||
delete fConfigurationDescriptors[i];
|
||||
}
|
||||
delete[] fConfigurationDescriptors;
|
||||
}
|
||||
if (fEndpointToIndex)
|
||||
delete[] fEndpointToIndex;
|
||||
if (fEndpointToInterface)
|
||||
delete[] fEndpointToInterface;
|
||||
}
|
||||
|
||||
bool
|
||||
USBDevice::InitCheck()
|
||||
{
|
||||
return fInitCheck;
|
||||
}
|
||||
|
||||
const char *
|
||||
USBDevice::Location() const
|
||||
{
|
||||
return fPath;
|
||||
}
|
||||
|
||||
uint8
|
||||
USBDevice::CountConfigurations() const
|
||||
{
|
||||
return fDeviceDescriptor.num_configurations;
|
||||
}
|
||||
|
||||
const usb_device_descriptor *
|
||||
USBDevice::Descriptor() const
|
||||
{
|
||||
return &fDeviceDescriptor;
|
||||
}
|
||||
|
||||
const usb_configuration_descriptor *
|
||||
USBDevice::ConfigurationDescriptor(uint8 index) const
|
||||
{
|
||||
if (index > CountConfigurations())
|
||||
return NULL;
|
||||
return (usb_configuration_descriptor *) fConfigurationDescriptors[index];
|
||||
}
|
||||
|
||||
const usb_configuration_descriptor *
|
||||
USBDevice::ActiveConfiguration() const
|
||||
{
|
||||
return (usb_configuration_descriptor *) fConfigurationDescriptors[fActiveConfiguration];
|
||||
}
|
||||
|
||||
uint8
|
||||
USBDevice::ActiveConfigurationIndex() const
|
||||
{
|
||||
return fActiveConfiguration;
|
||||
}
|
||||
|
||||
int USBDevice::ClaimInterface(uint8 interface)
|
||||
{
|
||||
if (interface > ActiveConfiguration()->number_interfaces)
|
||||
return LIBUSB_ERROR_NOT_FOUND;
|
||||
if (fClaimedInterfaces & (1U << interface))
|
||||
return LIBUSB_ERROR_BUSY;
|
||||
fClaimedInterfaces |= (1U << interface);
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int USBDevice::ReleaseInterface(uint8 interface)
|
||||
{
|
||||
fClaimedInterfaces &= ~(1U << interface);
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
USBDevice::CheckInterfacesFree(uint8 config)
|
||||
{
|
||||
if (fConfigToIndex.count(config) == 0)
|
||||
return LIBUSB_ERROR_NOT_FOUND;
|
||||
if (fClaimedInterfaces == 0)
|
||||
return fConfigToIndex[config];
|
||||
return LIBUSB_ERROR_BUSY;
|
||||
}
|
||||
|
||||
void
|
||||
USBDevice::SetActiveConfiguration(uint8 config_index)
|
||||
{
|
||||
fActiveConfiguration = config_index;
|
||||
}
|
||||
|
||||
uint8
|
||||
USBDevice::EndpointToIndex(uint8 address) const
|
||||
{
|
||||
return fEndpointToIndex[fActiveConfiguration][address];
|
||||
}
|
||||
|
||||
uint8
|
||||
USBDevice::EndpointToInterface(uint8 address) const
|
||||
{
|
||||
return fEndpointToInterface[fActiveConfiguration][address];
|
||||
}
|
||||
|
||||
int
|
||||
USBDevice::Initialise() //Do we need more error checking, etc? How to report?
|
||||
{
|
||||
int fRawFD = open(fPath, O_RDWR | O_CLOEXEC);
|
||||
if (fRawFD < 0)
|
||||
return B_ERROR;
|
||||
usb_raw_command command;
|
||||
command.device.descriptor = &fDeviceDescriptor;
|
||||
if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_DEVICE_DESCRIPTOR, &command, sizeof(command)) ||
|
||||
command.device.status != B_USB_RAW_STATUS_SUCCESS) {
|
||||
close(fRawFD);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
fConfigurationDescriptors = new(std::nothrow) unsigned char *[fDeviceDescriptor.num_configurations];
|
||||
fEndpointToIndex = new(std::nothrow) map<uint8,uint8> [fDeviceDescriptor.num_configurations];
|
||||
fEndpointToInterface = new(std::nothrow) map<uint8,uint8> [fDeviceDescriptor.num_configurations];
|
||||
for (uint8 i = 0; i < fDeviceDescriptor.num_configurations; i++) {
|
||||
usb_configuration_descriptor tmp_config;
|
||||
command.config.descriptor = &tmp_config;
|
||||
command.config.config_index = i;
|
||||
if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR, &command, sizeof(command)) ||
|
||||
command.config.status != B_USB_RAW_STATUS_SUCCESS) {
|
||||
usbi_err(NULL, "failed retrieving configuration descriptor");
|
||||
close(fRawFD);
|
||||
return B_ERROR;
|
||||
}
|
||||
fConfigToIndex[tmp_config.configuration_value] = i;
|
||||
fConfigurationDescriptors[i] = new(std::nothrow) unsigned char[tmp_config.total_length];
|
||||
|
||||
command.config_etc.descriptor = (usb_configuration_descriptor*)fConfigurationDescriptors[i];
|
||||
command.config_etc.length = tmp_config.total_length;
|
||||
command.config_etc.config_index = i;
|
||||
if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR_ETC, &command, sizeof(command)) ||
|
||||
command.config_etc.status != B_USB_RAW_STATUS_SUCCESS) {
|
||||
usbi_err(NULL, "failed retrieving full configuration descriptor");
|
||||
close(fRawFD);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
for (uint8 j = 0; j < tmp_config.number_interfaces; j++) {
|
||||
command.alternate.config_index = i;
|
||||
command.alternate.interface_index = j;
|
||||
if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ALT_INTERFACE_COUNT, &command, sizeof(command)) ||
|
||||
command.config.status != B_USB_RAW_STATUS_SUCCESS) {
|
||||
usbi_err(NULL, "failed retrieving number of alternate interfaces");
|
||||
close(fRawFD);
|
||||
return B_ERROR;
|
||||
}
|
||||
uint8 num_alternate = (uint8)command.alternate.alternate_info;
|
||||
for (uint8 k = 0; k < num_alternate; k++) {
|
||||
usb_interface_descriptor tmp_interface;
|
||||
command.interface_etc.config_index = i;
|
||||
command.interface_etc.interface_index = j;
|
||||
command.interface_etc.alternate_index = k;
|
||||
command.interface_etc.descriptor = &tmp_interface;
|
||||
if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_INTERFACE_DESCRIPTOR_ETC, &command, sizeof(command)) ||
|
||||
command.config.status != B_USB_RAW_STATUS_SUCCESS) {
|
||||
usbi_err(NULL, "failed retrieving interface descriptor");
|
||||
close(fRawFD);
|
||||
return B_ERROR;
|
||||
}
|
||||
for (uint8 l = 0; l < tmp_interface.num_endpoints; l++) {
|
||||
usb_endpoint_descriptor tmp_endpoint;
|
||||
command.endpoint_etc.config_index = i;
|
||||
command.endpoint_etc.interface_index = j;
|
||||
command.endpoint_etc.alternate_index = k;
|
||||
command.endpoint_etc.endpoint_index = l;
|
||||
command.endpoint_etc.descriptor = &tmp_endpoint;
|
||||
if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR_ETC, &command, sizeof(command)) ||
|
||||
command.config.status != B_USB_RAW_STATUS_SUCCESS) {
|
||||
usbi_err(NULL, "failed retrieving endpoint descriptor");
|
||||
close(fRawFD);
|
||||
return B_ERROR;
|
||||
}
|
||||
fEndpointToIndex[i][tmp_endpoint.endpoint_address] = l;
|
||||
fEndpointToInterface[i][tmp_endpoint.endpoint_address] = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
close(fRawFD);
|
||||
fInitCheck = true;
|
||||
return B_OK;
|
||||
}
|
||||
231
lib/libusb/libusb/os/haiku_usb_raw.cpp
Normal file
231
lib/libusb/libusb/os/haiku_usb_raw.cpp
Normal file
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Haiku Backend for libusb
|
||||
* Copyright © 2014 Akshay Jaggi <akshay1994.leo@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 <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <new>
|
||||
#include <vector>
|
||||
|
||||
#include "haiku_usb.h"
|
||||
|
||||
USBRoster gUsbRoster;
|
||||
int32 gInitCount = 0;
|
||||
|
||||
static int haiku_get_config_descriptor(struct libusb_device *, uint8_t,
|
||||
void *, size_t);
|
||||
|
||||
static int
|
||||
haiku_init(struct libusb_context *ctx)
|
||||
{
|
||||
UNUSED(ctx);
|
||||
if (atomic_add(&gInitCount, 1) == 0)
|
||||
return gUsbRoster.Start();
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
haiku_exit(struct libusb_context *ctx)
|
||||
{
|
||||
UNUSED(ctx);
|
||||
if (atomic_add(&gInitCount, -1) == 1)
|
||||
gUsbRoster.Stop();
|
||||
}
|
||||
|
||||
static int
|
||||
haiku_open(struct libusb_device_handle *dev_handle)
|
||||
{
|
||||
USBDevice *dev = *((USBDevice **)usbi_get_device_priv(dev_handle->dev));
|
||||
USBDeviceHandle *handle = new(std::nothrow) USBDeviceHandle(dev);
|
||||
if (handle == NULL)
|
||||
return LIBUSB_ERROR_NO_MEM;
|
||||
if (handle->InitCheck() == false) {
|
||||
delete handle;
|
||||
return LIBUSB_ERROR_NO_DEVICE;
|
||||
}
|
||||
*((USBDeviceHandle **)usbi_get_device_handle_priv(dev_handle)) = handle;
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
haiku_close(struct libusb_device_handle *dev_handle)
|
||||
{
|
||||
USBDeviceHandle **pHandle = (USBDeviceHandle **)usbi_get_device_handle_priv(dev_handle);
|
||||
USBDeviceHandle *handle = *pHandle;
|
||||
if (handle == NULL)
|
||||
return;
|
||||
delete handle;
|
||||
*pHandle = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
haiku_get_active_config_descriptor(struct libusb_device *device, void *buffer, size_t len)
|
||||
{
|
||||
USBDevice *dev = *((USBDevice **)usbi_get_device_priv(device));
|
||||
return haiku_get_config_descriptor(device, dev->ActiveConfigurationIndex(), buffer, len);
|
||||
}
|
||||
|
||||
static int
|
||||
haiku_get_config_descriptor(struct libusb_device *device, uint8_t config_index, void *buffer, size_t len)
|
||||
{
|
||||
USBDevice *dev = *((USBDevice **)usbi_get_device_priv(device));
|
||||
const usb_configuration_descriptor *config = dev->ConfigurationDescriptor(config_index);
|
||||
if (config == NULL) {
|
||||
usbi_err(DEVICE_CTX(device), "failed getting configuration descriptor");
|
||||
return LIBUSB_ERROR_IO;
|
||||
}
|
||||
if (len > config->total_length) {
|
||||
len = config->total_length;
|
||||
}
|
||||
memcpy(buffer, config, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
haiku_set_configuration(struct libusb_device_handle *dev_handle, int config)
|
||||
{
|
||||
USBDeviceHandle *handle= *((USBDeviceHandle **)usbi_get_device_handle_priv(dev_handle));
|
||||
if (config <= 0)
|
||||
return LIBUSB_ERROR_NOT_SUPPORTED; // cannot unconfigure
|
||||
return handle->SetConfiguration((uint8)config);
|
||||
}
|
||||
|
||||
static int
|
||||
haiku_claim_interface(struct libusb_device_handle *dev_handle, uint8_t interface_number)
|
||||
{
|
||||
USBDeviceHandle *handle = *((USBDeviceHandle **)usbi_get_device_handle_priv(dev_handle));
|
||||
return handle->ClaimInterface(interface_number);
|
||||
}
|
||||
|
||||
static int
|
||||
haiku_set_altsetting(struct libusb_device_handle *dev_handle, uint8_t interface_number, uint8_t altsetting)
|
||||
{
|
||||
USBDeviceHandle *handle = *((USBDeviceHandle **)usbi_get_device_handle_priv(dev_handle));
|
||||
return handle->SetAltSetting(interface_number, altsetting);
|
||||
}
|
||||
|
||||
static int
|
||||
haiku_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
|
||||
{
|
||||
USBDeviceHandle *handle = *((USBDeviceHandle **)usbi_get_device_handle_priv(dev_handle));
|
||||
return handle->ClearHalt(endpoint);
|
||||
}
|
||||
|
||||
static int
|
||||
haiku_release_interface(struct libusb_device_handle *dev_handle, uint8_t interface_number)
|
||||
{
|
||||
USBDeviceHandle *handle = *((USBDeviceHandle **)usbi_get_device_handle_priv(dev_handle));
|
||||
haiku_set_altsetting(dev_handle, interface_number, 0);
|
||||
return handle->ReleaseInterface(interface_number);
|
||||
}
|
||||
|
||||
static int
|
||||
haiku_submit_transfer(struct usbi_transfer *itransfer)
|
||||
{
|
||||
struct libusb_transfer *fLibusbTransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
||||
USBDeviceHandle *fDeviceHandle = *((USBDeviceHandle **)usbi_get_device_handle_priv(fLibusbTransfer->dev_handle));
|
||||
return fDeviceHandle->SubmitTransfer(itransfer);
|
||||
}
|
||||
|
||||
static int
|
||||
haiku_cancel_transfer(struct usbi_transfer *itransfer)
|
||||
{
|
||||
struct libusb_transfer *fLibusbTransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
||||
USBDeviceHandle *fDeviceHandle = *((USBDeviceHandle **)usbi_get_device_handle_priv(fLibusbTransfer->dev_handle));
|
||||
return fDeviceHandle->CancelTransfer(*((USBTransfer **)usbi_get_transfer_priv(itransfer)));
|
||||
}
|
||||
|
||||
static int
|
||||
haiku_handle_transfer_completion(struct usbi_transfer *itransfer)
|
||||
{
|
||||
USBTransfer **pTransfer = (USBTransfer **)usbi_get_transfer_priv(itransfer);
|
||||
USBTransfer *transfer = *pTransfer;
|
||||
|
||||
usbi_mutex_lock(&itransfer->lock);
|
||||
if (transfer->IsCancelled()) {
|
||||
delete transfer;
|
||||
*pTransfer = NULL;
|
||||
usbi_mutex_unlock(&itransfer->lock);
|
||||
if (itransfer->transferred < 0)
|
||||
itransfer->transferred = 0;
|
||||
return usbi_handle_transfer_cancellation(itransfer);
|
||||
}
|
||||
libusb_transfer_status status = LIBUSB_TRANSFER_COMPLETED;
|
||||
if (itransfer->transferred < 0) {
|
||||
usbi_err(ITRANSFER_CTX(itransfer), "error in transfer");
|
||||
status = LIBUSB_TRANSFER_ERROR;
|
||||
itransfer->transferred = 0;
|
||||
}
|
||||
delete transfer;
|
||||
*pTransfer = NULL;
|
||||
usbi_mutex_unlock(&itransfer->lock);
|
||||
return usbi_handle_transfer_completion(itransfer, status);
|
||||
}
|
||||
|
||||
const struct usbi_os_backend usbi_backend = {
|
||||
/*.name =*/ "Haiku usbfs",
|
||||
/*.caps =*/ 0,
|
||||
/*.init =*/ haiku_init,
|
||||
/*.exit =*/ haiku_exit,
|
||||
/*.set_option =*/ NULL,
|
||||
/*.get_device_list =*/ NULL,
|
||||
/*.hotplug_poll =*/ NULL,
|
||||
/*.wrap_sys_device =*/ NULL,
|
||||
/*.open =*/ haiku_open,
|
||||
/*.close =*/ haiku_close,
|
||||
|
||||
/*.get_active_config_descriptor =*/ haiku_get_active_config_descriptor,
|
||||
/*.get_config_descriptor =*/ haiku_get_config_descriptor,
|
||||
/*.get_config_descriptor_by_value =*/ NULL,
|
||||
|
||||
/*.get_configuration =*/ NULL,
|
||||
/*.set_configuration =*/ haiku_set_configuration,
|
||||
|
||||
/*.claim_interface =*/ haiku_claim_interface,
|
||||
/*.release_interface =*/ haiku_release_interface,
|
||||
/*.set_interface_altsetting =*/ haiku_set_altsetting,
|
||||
|
||||
/*.clear_halt =*/ haiku_clear_halt,
|
||||
/*.reset_device =*/ NULL,
|
||||
|
||||
/*.alloc_streams =*/ NULL,
|
||||
/*.free_streams =*/ NULL,
|
||||
|
||||
/*.dev_mem_alloc =*/ NULL,
|
||||
/*.dev_mem_free =*/ NULL,
|
||||
|
||||
/*.kernel_driver_active =*/ NULL,
|
||||
/*.detach_kernel_driver =*/ NULL,
|
||||
/*.attach_kernel_driver =*/ NULL,
|
||||
|
||||
/*.destroy_device =*/ NULL,
|
||||
|
||||
/*.submit_transfer =*/ haiku_submit_transfer,
|
||||
/*.cancel_transfer =*/ haiku_cancel_transfer,
|
||||
/*.clear_transfer_priv =*/ NULL,
|
||||
|
||||
/*.handle_events =*/ NULL,
|
||||
/*.handle_transfer_completion =*/ haiku_handle_transfer_completion,
|
||||
|
||||
/*.context_priv_size =*/ 0,
|
||||
/*.device_priv_size =*/ sizeof(USBDevice *),
|
||||
/*.device_handle_priv_size =*/ sizeof(USBDeviceHandle *),
|
||||
/*.transfer_priv_size =*/ sizeof(USBTransfer *),
|
||||
};
|
||||
188
lib/libusb/libusb/os/haiku_usb_raw.h
Normal file
188
lib/libusb/libusb/os/haiku_usb_raw.h
Normal file
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright 2006-2008, Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef _USB_RAW_H_
|
||||
#define _USB_RAW_H_
|
||||
|
||||
#include <USB3.h>
|
||||
|
||||
#define B_USB_RAW_PROTOCOL_VERSION 0x0015
|
||||
#define B_USB_RAW_ACTIVE_ALTERNATE 0xffffffff
|
||||
|
||||
typedef enum {
|
||||
B_USB_RAW_COMMAND_GET_VERSION = 0x1000,
|
||||
|
||||
B_USB_RAW_COMMAND_GET_DEVICE_DESCRIPTOR = 0x2000,
|
||||
B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR,
|
||||
B_USB_RAW_COMMAND_GET_INTERFACE_DESCRIPTOR,
|
||||
B_USB_RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR,
|
||||
B_USB_RAW_COMMAND_GET_STRING_DESCRIPTOR,
|
||||
B_USB_RAW_COMMAND_GET_GENERIC_DESCRIPTOR,
|
||||
B_USB_RAW_COMMAND_GET_ALT_INTERFACE_COUNT,
|
||||
B_USB_RAW_COMMAND_GET_ACTIVE_ALT_INTERFACE_INDEX,
|
||||
B_USB_RAW_COMMAND_GET_INTERFACE_DESCRIPTOR_ETC,
|
||||
B_USB_RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR_ETC,
|
||||
B_USB_RAW_COMMAND_GET_GENERIC_DESCRIPTOR_ETC,
|
||||
B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR_ETC,
|
||||
|
||||
B_USB_RAW_COMMAND_SET_CONFIGURATION = 0x3000,
|
||||
B_USB_RAW_COMMAND_SET_FEATURE,
|
||||
B_USB_RAW_COMMAND_CLEAR_FEATURE,
|
||||
B_USB_RAW_COMMAND_GET_STATUS,
|
||||
B_USB_RAW_COMMAND_GET_DESCRIPTOR,
|
||||
B_USB_RAW_COMMAND_SET_ALT_INTERFACE,
|
||||
|
||||
B_USB_RAW_COMMAND_CONTROL_TRANSFER = 0x4000,
|
||||
B_USB_RAW_COMMAND_INTERRUPT_TRANSFER,
|
||||
B_USB_RAW_COMMAND_BULK_TRANSFER,
|
||||
B_USB_RAW_COMMAND_ISOCHRONOUS_TRANSFER
|
||||
} usb_raw_command_id;
|
||||
|
||||
|
||||
typedef enum {
|
||||
B_USB_RAW_STATUS_SUCCESS = 0,
|
||||
|
||||
B_USB_RAW_STATUS_FAILED,
|
||||
B_USB_RAW_STATUS_ABORTED,
|
||||
B_USB_RAW_STATUS_STALLED,
|
||||
B_USB_RAW_STATUS_CRC_ERROR,
|
||||
B_USB_RAW_STATUS_TIMEOUT,
|
||||
|
||||
B_USB_RAW_STATUS_INVALID_CONFIGURATION,
|
||||
B_USB_RAW_STATUS_INVALID_INTERFACE,
|
||||
B_USB_RAW_STATUS_INVALID_ENDPOINT,
|
||||
B_USB_RAW_STATUS_INVALID_STRING,
|
||||
|
||||
B_USB_RAW_STATUS_NO_MEMORY
|
||||
} usb_raw_command_status;
|
||||
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
status_t status;
|
||||
} version;
|
||||
|
||||
struct {
|
||||
status_t status;
|
||||
usb_device_descriptor *descriptor;
|
||||
} device;
|
||||
|
||||
struct {
|
||||
status_t status;
|
||||
usb_configuration_descriptor *descriptor;
|
||||
uint32 config_index;
|
||||
} config;
|
||||
|
||||
struct {
|
||||
status_t status;
|
||||
usb_configuration_descriptor *descriptor;
|
||||
uint32 config_index;
|
||||
size_t length;
|
||||
} config_etc;
|
||||
|
||||
struct {
|
||||
status_t status;
|
||||
uint32 alternate_info;
|
||||
uint32 config_index;
|
||||
uint32 interface_index;
|
||||
} alternate;
|
||||
|
||||
struct {
|
||||
status_t status;
|
||||
usb_interface_descriptor *descriptor;
|
||||
uint32 config_index;
|
||||
uint32 interface_index;
|
||||
} interface;
|
||||
|
||||
struct {
|
||||
status_t status;
|
||||
usb_interface_descriptor *descriptor;
|
||||
uint32 config_index;
|
||||
uint32 interface_index;
|
||||
uint32 alternate_index;
|
||||
} interface_etc;
|
||||
|
||||
struct {
|
||||
status_t status;
|
||||
usb_endpoint_descriptor *descriptor;
|
||||
uint32 config_index;
|
||||
uint32 interface_index;
|
||||
uint32 endpoint_index;
|
||||
} endpoint;
|
||||
|
||||
struct {
|
||||
status_t status;
|
||||
usb_endpoint_descriptor *descriptor;
|
||||
uint32 config_index;
|
||||
uint32 interface_index;
|
||||
uint32 alternate_index;
|
||||
uint32 endpoint_index;
|
||||
} endpoint_etc;
|
||||
|
||||
struct {
|
||||
status_t status;
|
||||
usb_descriptor *descriptor;
|
||||
uint32 config_index;
|
||||
uint32 interface_index;
|
||||
uint32 generic_index;
|
||||
size_t length;
|
||||
} generic;
|
||||
|
||||
struct {
|
||||
status_t status;
|
||||
usb_descriptor *descriptor;
|
||||
uint32 config_index;
|
||||
uint32 interface_index;
|
||||
uint32 alternate_index;
|
||||
uint32 generic_index;
|
||||
size_t length;
|
||||
} generic_etc;
|
||||
|
||||
struct {
|
||||
status_t status;
|
||||
usb_string_descriptor *descriptor;
|
||||
uint32 string_index;
|
||||
size_t length;
|
||||
} string;
|
||||
|
||||
struct {
|
||||
status_t status;
|
||||
uint8 type;
|
||||
uint8 index;
|
||||
uint16 language_id;
|
||||
void *data;
|
||||
size_t length;
|
||||
} descriptor;
|
||||
|
||||
struct {
|
||||
status_t status;
|
||||
uint8 request_type;
|
||||
uint8 request;
|
||||
uint16 value;
|
||||
uint16 index;
|
||||
uint16 length;
|
||||
void *data;
|
||||
} control;
|
||||
|
||||
struct {
|
||||
status_t status;
|
||||
uint32 interface;
|
||||
uint32 endpoint;
|
||||
void *data;
|
||||
size_t length;
|
||||
} transfer;
|
||||
|
||||
struct {
|
||||
status_t status;
|
||||
uint32 interface;
|
||||
uint32 endpoint;
|
||||
void *data;
|
||||
size_t length;
|
||||
usb_iso_packet_descriptor *packet_descriptors;
|
||||
uint32 packet_count;
|
||||
} isochronous;
|
||||
} usb_raw_command;
|
||||
|
||||
#endif // _USB_RAW_H_
|
||||
401
lib/libusb/libusb/os/linux_netlink.c
Normal file
401
lib/libusb/libusb/os/linux_netlink.c
Normal file
@@ -0,0 +1,401 @@
|
||||
/* -*- Mode: C; c-basic-offset:8 ; indent-tabs-mode:t -*- */
|
||||
/*
|
||||
* Linux usbfs backend for libusb
|
||||
* Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
|
||||
* Copyright (c) 2013 Nathan Hjelm <hjelmn@mac.com>
|
||||
* Copyright (c) 2016 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 "linux_usbfs.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef HAVE_ASM_TYPES_H
|
||||
#include <asm/types.h>
|
||||
#endif
|
||||
#include <sys/socket.h>
|
||||
#include <linux/netlink.h>
|
||||
|
||||
#define NL_GROUP_KERNEL 1
|
||||
|
||||
#ifndef SOCK_CLOEXEC
|
||||
#define SOCK_CLOEXEC 0
|
||||
#endif
|
||||
|
||||
#ifndef SOCK_NONBLOCK
|
||||
#define SOCK_NONBLOCK 0
|
||||
#endif
|
||||
|
||||
static int linux_netlink_socket = -1;
|
||||
static usbi_event_t netlink_control_event = USBI_INVALID_EVENT;
|
||||
static pthread_t libusb_linux_event_thread;
|
||||
|
||||
static void *linux_netlink_event_thread_main(void *arg);
|
||||
|
||||
static int set_fd_cloexec_nb(int fd, int socktype)
|
||||
{
|
||||
int flags;
|
||||
|
||||
#if defined(FD_CLOEXEC)
|
||||
/* Make sure the netlink socket file descriptor is marked as CLOEXEC */
|
||||
if (!(socktype & SOCK_CLOEXEC)) {
|
||||
flags = fcntl(fd, F_GETFD);
|
||||
if (flags == -1) {
|
||||
usbi_err(NULL, "failed to get netlink fd flags, errno=%d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
|
||||
usbi_err(NULL, "failed to set netlink fd flags, errno=%d", errno);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Make sure the netlink socket is non-blocking */
|
||||
if (!(socktype & SOCK_NONBLOCK)) {
|
||||
flags = fcntl(fd, F_GETFL);
|
||||
if (flags == -1) {
|
||||
usbi_err(NULL, "failed to get netlink fd status flags, errno=%d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
|
||||
usbi_err(NULL, "failed to set netlink fd status flags, errno=%d", errno);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int linux_netlink_start_event_monitor(void)
|
||||
{
|
||||
struct sockaddr_nl sa_nl = { .nl_family = AF_NETLINK, .nl_groups = NL_GROUP_KERNEL };
|
||||
int socktype = SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC;
|
||||
int opt = 1;
|
||||
int ret;
|
||||
|
||||
linux_netlink_socket = socket(PF_NETLINK, socktype, NETLINK_KOBJECT_UEVENT);
|
||||
if (linux_netlink_socket == -1 && errno == EINVAL) {
|
||||
usbi_dbg(NULL, "failed to create netlink socket of type %d, attempting SOCK_RAW", socktype);
|
||||
socktype = SOCK_RAW;
|
||||
linux_netlink_socket = socket(PF_NETLINK, socktype, NETLINK_KOBJECT_UEVENT);
|
||||
}
|
||||
|
||||
if (linux_netlink_socket == -1) {
|
||||
usbi_err(NULL, "failed to create netlink socket, errno=%d", errno);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = set_fd_cloexec_nb(linux_netlink_socket, socktype);
|
||||
if (ret == -1)
|
||||
goto err_close_socket;
|
||||
|
||||
ret = bind(linux_netlink_socket, (struct sockaddr *)&sa_nl, sizeof(sa_nl));
|
||||
if (ret == -1) {
|
||||
usbi_err(NULL, "failed to bind netlink socket, errno=%d", errno);
|
||||
goto err_close_socket;
|
||||
}
|
||||
|
||||
ret = setsockopt(linux_netlink_socket, SOL_SOCKET, SO_PASSCRED, &opt, sizeof(opt));
|
||||
if (ret == -1) {
|
||||
usbi_err(NULL, "failed to set netlink socket SO_PASSCRED option, errno=%d", errno);
|
||||
goto err_close_socket;
|
||||
}
|
||||
|
||||
ret = usbi_create_event(&netlink_control_event);
|
||||
if (ret) {
|
||||
usbi_err(NULL, "failed to create netlink control event");
|
||||
goto err_close_socket;
|
||||
}
|
||||
|
||||
ret = pthread_create(&libusb_linux_event_thread, NULL, linux_netlink_event_thread_main, NULL);
|
||||
if (ret != 0) {
|
||||
usbi_err(NULL, "failed to create netlink event thread (%d)", ret);
|
||||
goto err_destroy_event;
|
||||
}
|
||||
|
||||
return LIBUSB_SUCCESS;
|
||||
|
||||
err_destroy_event:
|
||||
usbi_destroy_event(&netlink_control_event);
|
||||
netlink_control_event = (usbi_event_t)USBI_INVALID_EVENT;
|
||||
err_close_socket:
|
||||
close(linux_netlink_socket);
|
||||
linux_netlink_socket = -1;
|
||||
err:
|
||||
return LIBUSB_ERROR_OTHER;
|
||||
}
|
||||
|
||||
int linux_netlink_stop_event_monitor(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
assert(linux_netlink_socket != -1);
|
||||
|
||||
/* Signal the control event and wait for the thread to exit */
|
||||
usbi_signal_event(&netlink_control_event);
|
||||
|
||||
ret = pthread_join(libusb_linux_event_thread, NULL);
|
||||
if (ret)
|
||||
usbi_warn(NULL, "failed to join netlink event thread (%d)", ret);
|
||||
|
||||
usbi_destroy_event(&netlink_control_event);
|
||||
netlink_control_event = (usbi_event_t)USBI_INVALID_EVENT;
|
||||
|
||||
close(linux_netlink_socket);
|
||||
linux_netlink_socket = -1;
|
||||
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
static const char *netlink_message_parse(const char *buffer, size_t len, const char *key)
|
||||
{
|
||||
const char *end = buffer + len;
|
||||
size_t keylen = strlen(key);
|
||||
|
||||
while (buffer < end && *buffer) {
|
||||
if (strncmp(buffer, key, keylen) == 0 && buffer[keylen] == '=')
|
||||
return buffer + keylen + 1;
|
||||
buffer += strlen(buffer) + 1;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* parse parts of netlink message common to both libudev and the kernel */
|
||||
static int linux_netlink_parse(const char *buffer, size_t len, int *detached,
|
||||
const char **sys_name, uint8_t *busnum, uint8_t *devaddr)
|
||||
{
|
||||
const char *tmp, *slash;
|
||||
|
||||
errno = 0;
|
||||
|
||||
*sys_name = NULL;
|
||||
*detached = 0;
|
||||
*busnum = 0;
|
||||
*devaddr = 0;
|
||||
|
||||
tmp = netlink_message_parse(buffer, len, "ACTION");
|
||||
if (!tmp) {
|
||||
return -1;
|
||||
} else if (strcmp(tmp, "remove") == 0) {
|
||||
*detached = 1;
|
||||
} else if (strcmp(tmp, "add") != 0) {
|
||||
usbi_dbg(NULL, "unknown device action %s", tmp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check that this is a usb message */
|
||||
tmp = netlink_message_parse(buffer, len, "SUBSYSTEM");
|
||||
if (!tmp || strcmp(tmp, "usb") != 0) {
|
||||
/* not usb. ignore */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check that this is an actual usb device */
|
||||
tmp = netlink_message_parse(buffer, len, "DEVTYPE");
|
||||
if (!tmp || strcmp(tmp, "usb_device") != 0) {
|
||||
/* not usb. ignore */
|
||||
return -1;
|
||||
}
|
||||
|
||||
tmp = netlink_message_parse(buffer, len, "BUSNUM");
|
||||
if (tmp) {
|
||||
*busnum = (uint8_t)(strtoul(tmp, NULL, 10) & 0xff);
|
||||
if (errno) {
|
||||
errno = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tmp = netlink_message_parse(buffer, len, "DEVNUM");
|
||||
if (NULL == tmp)
|
||||
return -1;
|
||||
|
||||
*devaddr = (uint8_t)(strtoul(tmp, NULL, 10) & 0xff);
|
||||
if (errno) {
|
||||
errno = 0;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
/* no bus number. try "DEVICE" */
|
||||
tmp = netlink_message_parse(buffer, len, "DEVICE");
|
||||
if (!tmp) {
|
||||
/* not usb. ignore */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Parse a device path such as /dev/bus/usb/003/004 */
|
||||
slash = strrchr(tmp, '/');
|
||||
if (!slash)
|
||||
return -1;
|
||||
|
||||
*busnum = (uint8_t)(strtoul(slash - 3, NULL, 10) & 0xff);
|
||||
if (errno) {
|
||||
errno = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*devaddr = (uint8_t)(strtoul(slash + 1, NULL, 10) & 0xff);
|
||||
if (errno) {
|
||||
errno = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp = netlink_message_parse(buffer, len, "DEVPATH");
|
||||
if (!tmp)
|
||||
return -1;
|
||||
|
||||
slash = strrchr(tmp, '/');
|
||||
if (slash)
|
||||
*sys_name = slash + 1;
|
||||
|
||||
/* found a usb device */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int linux_netlink_read_message(void)
|
||||
{
|
||||
char cred_buffer[CMSG_SPACE(sizeof(struct ucred))];
|
||||
char msg_buffer[2048];
|
||||
const char *sys_name = NULL;
|
||||
uint8_t busnum, devaddr;
|
||||
int detached, r;
|
||||
ssize_t len;
|
||||
struct cmsghdr *cmsg;
|
||||
struct ucred *cred;
|
||||
struct sockaddr_nl sa_nl;
|
||||
struct iovec iov = { .iov_base = msg_buffer, .iov_len = sizeof(msg_buffer) };
|
||||
struct msghdr msg = {
|
||||
.msg_iov = &iov, .msg_iovlen = 1,
|
||||
.msg_control = cred_buffer, .msg_controllen = sizeof(cred_buffer),
|
||||
.msg_name = &sa_nl, .msg_namelen = sizeof(sa_nl)
|
||||
};
|
||||
|
||||
/* read netlink message */
|
||||
len = recvmsg(linux_netlink_socket, &msg, 0);
|
||||
if (len == -1) {
|
||||
if (errno != EAGAIN && errno != EINTR)
|
||||
usbi_err(NULL, "error receiving message from netlink, errno=%d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len < 32 || (msg.msg_flags & MSG_TRUNC)) {
|
||||
usbi_err(NULL, "invalid netlink message length");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sa_nl.nl_groups != NL_GROUP_KERNEL || sa_nl.nl_pid != 0) {
|
||||
usbi_dbg(NULL, "ignoring netlink message from unknown group/PID (%u/%u)",
|
||||
(unsigned int)sa_nl.nl_groups, (unsigned int)sa_nl.nl_pid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS) {
|
||||
usbi_dbg(NULL, "ignoring netlink message with no sender credentials");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cred = (struct ucred *)CMSG_DATA(cmsg);
|
||||
if (cred->uid != 0) {
|
||||
usbi_dbg(NULL, "ignoring netlink message with non-zero sender UID %u", (unsigned int)cred->uid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = linux_netlink_parse(msg_buffer, (size_t)len, &detached, &sys_name, &busnum, &devaddr);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
usbi_dbg(NULL, "netlink hotplug found device busnum: %hhu, devaddr: %hhu, sys_name: %s, removed: %s",
|
||||
busnum, devaddr, sys_name, detached ? "yes" : "no");
|
||||
|
||||
/* signal device is available (or not) to all contexts */
|
||||
if (detached)
|
||||
linux_device_disconnected(busnum, devaddr);
|
||||
else
|
||||
linux_hotplug_enumerate(busnum, devaddr, sys_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *linux_netlink_event_thread_main(void *arg)
|
||||
{
|
||||
struct pollfd fds[] = {
|
||||
{ .fd = USBI_EVENT_OS_HANDLE(&netlink_control_event),
|
||||
.events = USBI_EVENT_POLL_EVENTS },
|
||||
{ .fd = linux_netlink_socket,
|
||||
.events = POLLIN },
|
||||
};
|
||||
int r;
|
||||
|
||||
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(NULL, "netlink event thread entering");
|
||||
|
||||
while (1) {
|
||||
r = poll(fds, 2, -1);
|
||||
if (r == -1) {
|
||||
/* check for temporary failure */
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
usbi_err(NULL, "poll() failed, errno=%d", errno);
|
||||
break;
|
||||
}
|
||||
if (fds[0].revents) {
|
||||
/* activity on control event, exit */
|
||||
break;
|
||||
}
|
||||
if (fds[1].revents) {
|
||||
usbi_mutex_static_lock(&linux_hotplug_lock);
|
||||
linux_netlink_read_message();
|
||||
usbi_mutex_static_unlock(&linux_hotplug_lock);
|
||||
}
|
||||
}
|
||||
|
||||
usbi_dbg(NULL, "netlink event thread exiting");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void linux_netlink_hotplug_poll(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
usbi_mutex_static_lock(&linux_hotplug_lock);
|
||||
do {
|
||||
r = linux_netlink_read_message();
|
||||
} while (r == 0);
|
||||
usbi_mutex_static_unlock(&linux_hotplug_lock);
|
||||
}
|
||||
321
lib/libusb/libusb/os/linux_udev.c
Normal file
321
lib/libusb/libusb/os/linux_udev.c
Normal file
@@ -0,0 +1,321 @@
|
||||
/* -*- Mode: C; c-basic-offset:8 ; indent-tabs-mode:t -*- */
|
||||
/*
|
||||
* Linux usbfs backend for libusb
|
||||
* Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
|
||||
* Copyright (c) 2012-2013 Nathan Hjelm <hjelmn@mac.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 "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 */
|
||||
static struct udev *udev_ctx = NULL;
|
||||
static int udev_monitor_fd = -1;
|
||||
static usbi_event_t udev_control_event = USBI_INVALID_EVENT;
|
||||
static struct udev_monitor *udev_monitor = NULL;
|
||||
static pthread_t linux_event_thread;
|
||||
|
||||
static void udev_hotplug_event(struct udev_device *udev_dev);
|
||||
static void *linux_udev_event_thread_main(void *arg);
|
||||
|
||||
int linux_udev_start_event_monitor(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
assert(udev_ctx == NULL);
|
||||
udev_ctx = udev_new();
|
||||
if (!udev_ctx) {
|
||||
usbi_err(NULL, "could not create udev context");
|
||||
goto err;
|
||||
}
|
||||
|
||||
udev_monitor = udev_monitor_new_from_netlink(udev_ctx, "udev");
|
||||
if (!udev_monitor) {
|
||||
usbi_err(NULL, "could not initialize udev monitor");
|
||||
goto err_free_ctx;
|
||||
}
|
||||
|
||||
r = udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", "usb_device");
|
||||
if (r) {
|
||||
usbi_err(NULL, "could not initialize udev monitor filter for \"usb\" subsystem");
|
||||
goto err_free_monitor;
|
||||
}
|
||||
|
||||
if (udev_monitor_enable_receiving(udev_monitor)) {
|
||||
usbi_err(NULL, "failed to enable the udev monitor");
|
||||
goto err_free_monitor;
|
||||
}
|
||||
|
||||
udev_monitor_fd = udev_monitor_get_fd(udev_monitor);
|
||||
|
||||
#if defined(FD_CLOEXEC)
|
||||
/* Make sure the udev file descriptor is marked as CLOEXEC */
|
||||
r = fcntl(udev_monitor_fd, F_GETFD);
|
||||
if (r == -1) {
|
||||
usbi_err(NULL, "failed to get udev monitor fd flags, errno=%d", errno);
|
||||
goto err_free_monitor;
|
||||
}
|
||||
if (!(r & FD_CLOEXEC)) {
|
||||
if (fcntl(udev_monitor_fd, F_SETFD, r | FD_CLOEXEC) == -1) {
|
||||
usbi_err(NULL, "failed to set udev monitor fd flags, errno=%d", errno);
|
||||
goto err_free_monitor;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Some older versions of udev are not non-blocking by default,
|
||||
* so make sure this is set */
|
||||
r = fcntl(udev_monitor_fd, F_GETFL);
|
||||
if (r == -1) {
|
||||
usbi_err(NULL, "failed to get udev monitor fd status flags, errno=%d", errno);
|
||||
goto err_free_monitor;
|
||||
}
|
||||
if (!(r & O_NONBLOCK)) {
|
||||
if (fcntl(udev_monitor_fd, F_SETFL, r | O_NONBLOCK) == -1) {
|
||||
usbi_err(NULL, "failed to set udev monitor fd status flags, errno=%d", errno);
|
||||
goto err_free_monitor;
|
||||
}
|
||||
}
|
||||
|
||||
r = usbi_create_event(&udev_control_event);
|
||||
if (r) {
|
||||
usbi_err(NULL, "failed to create udev control event");
|
||||
goto err_free_monitor;
|
||||
}
|
||||
|
||||
r = pthread_create(&linux_event_thread, NULL, linux_udev_event_thread_main, NULL);
|
||||
if (r) {
|
||||
usbi_err(NULL, "failed to create hotplug event thread (%d)", r);
|
||||
goto err_destroy_event;
|
||||
}
|
||||
|
||||
return LIBUSB_SUCCESS;
|
||||
|
||||
err_destroy_event:
|
||||
usbi_destroy_event(&udev_control_event);
|
||||
udev_control_event = (usbi_event_t)USBI_INVALID_EVENT;
|
||||
err_free_monitor:
|
||||
udev_monitor_unref(udev_monitor);
|
||||
udev_monitor = NULL;
|
||||
udev_monitor_fd = -1;
|
||||
err_free_ctx:
|
||||
udev_unref(udev_ctx);
|
||||
err:
|
||||
udev_ctx = NULL;
|
||||
return LIBUSB_ERROR_OTHER;
|
||||
}
|
||||
|
||||
int linux_udev_stop_event_monitor(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
assert(udev_ctx != NULL);
|
||||
assert(udev_monitor != NULL);
|
||||
assert(udev_monitor_fd != -1);
|
||||
|
||||
/* Signal the control event and wait for the thread to exit */
|
||||
usbi_signal_event(&udev_control_event);
|
||||
|
||||
r = pthread_join(linux_event_thread, NULL);
|
||||
if (r)
|
||||
usbi_warn(NULL, "failed to join hotplug event thread (%d)", r);
|
||||
|
||||
usbi_destroy_event(&udev_control_event);
|
||||
udev_control_event = (usbi_event_t)USBI_INVALID_EVENT;
|
||||
|
||||
/* Release the udev monitor */
|
||||
udev_monitor_unref(udev_monitor);
|
||||
udev_monitor = NULL;
|
||||
udev_monitor_fd = -1;
|
||||
|
||||
/* Clean up the udev context */
|
||||
udev_unref(udev_ctx);
|
||||
udev_ctx = NULL;
|
||||
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
static void *linux_udev_event_thread_main(void *arg)
|
||||
{
|
||||
struct pollfd fds[] = {
|
||||
{ .fd = USBI_EVENT_OS_HANDLE(&udev_control_event),
|
||||
.events = USBI_EVENT_POLL_EVENTS },
|
||||
{ .fd = udev_monitor_fd,
|
||||
.events = POLLIN },
|
||||
};
|
||||
struct udev_device *udev_dev;
|
||||
int r;
|
||||
|
||||
UNUSED(arg);
|
||||
|
||||
#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(NULL, "udev event thread entering");
|
||||
|
||||
while (1) {
|
||||
r = poll(fds, 2, -1);
|
||||
if (r == -1) {
|
||||
/* check for temporary failure */
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
usbi_err(NULL, "poll() failed, errno=%d", errno);
|
||||
break;
|
||||
}
|
||||
if (fds[0].revents) {
|
||||
/* activity on control event, exit */
|
||||
break;
|
||||
}
|
||||
if (fds[1].revents) {
|
||||
usbi_mutex_static_lock(&linux_hotplug_lock);
|
||||
udev_dev = udev_monitor_receive_device(udev_monitor);
|
||||
if (udev_dev)
|
||||
udev_hotplug_event(udev_dev);
|
||||
usbi_mutex_static_unlock(&linux_hotplug_lock);
|
||||
}
|
||||
}
|
||||
|
||||
usbi_dbg(NULL, "udev event thread exiting");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int udev_device_info(struct libusb_context *ctx, int detached,
|
||||
struct udev_device *udev_dev, uint8_t *busnum,
|
||||
uint8_t *devaddr, const char **sys_name) {
|
||||
const char *dev_node;
|
||||
|
||||
dev_node = udev_device_get_devnode(udev_dev);
|
||||
if (!dev_node) {
|
||||
return LIBUSB_ERROR_OTHER;
|
||||
}
|
||||
|
||||
*sys_name = udev_device_get_sysname(udev_dev);
|
||||
if (!*sys_name) {
|
||||
return LIBUSB_ERROR_OTHER;
|
||||
}
|
||||
|
||||
return linux_get_device_address(ctx, detached, busnum, devaddr,
|
||||
dev_node, *sys_name, -1);
|
||||
}
|
||||
|
||||
static void udev_hotplug_event(struct udev_device *udev_dev)
|
||||
{
|
||||
const char *udev_action;
|
||||
const char *sys_name = NULL;
|
||||
uint8_t busnum = 0, devaddr = 0;
|
||||
int detached;
|
||||
int r;
|
||||
|
||||
do {
|
||||
udev_action = udev_device_get_action(udev_dev);
|
||||
if (!udev_action) {
|
||||
break;
|
||||
}
|
||||
|
||||
detached = !strncmp(udev_action, "remove", 6);
|
||||
|
||||
r = udev_device_info(NULL, detached, udev_dev, &busnum, &devaddr, &sys_name);
|
||||
if (LIBUSB_SUCCESS != r) {
|
||||
break;
|
||||
}
|
||||
|
||||
usbi_dbg(NULL, "udev hotplug event. action: %s.", udev_action);
|
||||
|
||||
if (strncmp(udev_action, "add", 3) == 0) {
|
||||
linux_hotplug_enumerate(busnum, devaddr, sys_name);
|
||||
} else if (detached) {
|
||||
linux_device_disconnected(busnum, devaddr);
|
||||
} else if (strncmp(udev_action, "bind", 4) == 0) {
|
||||
/* silently ignore "known unhandled" action */
|
||||
} else {
|
||||
usbi_err(NULL, "ignoring udev action %s", udev_action);
|
||||
}
|
||||
} while (0);
|
||||
|
||||
udev_device_unref(udev_dev);
|
||||
}
|
||||
|
||||
int linux_udev_scan_devices(struct libusb_context *ctx)
|
||||
{
|
||||
struct udev_enumerate *enumerator;
|
||||
struct udev_list_entry *devices, *entry;
|
||||
struct udev_device *udev_dev;
|
||||
const char *sys_name;
|
||||
int r;
|
||||
|
||||
assert(udev_ctx != NULL);
|
||||
|
||||
enumerator = udev_enumerate_new(udev_ctx);
|
||||
if (NULL == enumerator) {
|
||||
usbi_err(ctx, "error creating udev enumerator");
|
||||
return LIBUSB_ERROR_OTHER;
|
||||
}
|
||||
|
||||
udev_enumerate_add_match_subsystem(enumerator, "usb");
|
||||
udev_enumerate_add_match_property(enumerator, "DEVTYPE", "usb_device");
|
||||
udev_enumerate_scan_devices(enumerator);
|
||||
devices = udev_enumerate_get_list_entry(enumerator);
|
||||
|
||||
entry = NULL;
|
||||
udev_list_entry_foreach(entry, devices) {
|
||||
const char *path = udev_list_entry_get_name(entry);
|
||||
uint8_t busnum = 0, devaddr = 0;
|
||||
|
||||
udev_dev = udev_device_new_from_syspath(udev_ctx, path);
|
||||
|
||||
r = udev_device_info(ctx, 0, udev_dev, &busnum, &devaddr, &sys_name);
|
||||
if (r) {
|
||||
udev_device_unref(udev_dev);
|
||||
continue;
|
||||
}
|
||||
|
||||
linux_enumerate_device(ctx, busnum, devaddr, sys_name);
|
||||
udev_device_unref(udev_dev);
|
||||
}
|
||||
|
||||
udev_enumerate_unref(enumerator);
|
||||
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
void linux_udev_hotplug_poll(void)
|
||||
{
|
||||
struct udev_device *udev_dev;
|
||||
|
||||
usbi_mutex_static_lock(&linux_hotplug_lock);
|
||||
do {
|
||||
udev_dev = udev_monitor_receive_device(udev_monitor);
|
||||
if (udev_dev) {
|
||||
usbi_dbg(NULL, "Handling hotplug event from hotplug_poll");
|
||||
udev_hotplug_event(udev_dev);
|
||||
}
|
||||
} while (udev_dev);
|
||||
usbi_mutex_static_unlock(&linux_hotplug_lock);
|
||||
}
|
||||
2829
lib/libusb/libusb/os/linux_usbfs.c
Normal file
2829
lib/libusb/libusb/os/linux_usbfs.c
Normal file
File diff suppressed because it is too large
Load Diff
221
lib/libusb/libusb/os/linux_usbfs.h
Normal file
221
lib/libusb/libusb/os/linux_usbfs.h
Normal file
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* usbfs header structures
|
||||
* Copyright © 2007 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright © 2001 Johannes Erdfelt <johannes@erdfelt.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_USBFS_H
|
||||
#define LIBUSB_USBFS_H
|
||||
|
||||
#include <linux/magic.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define SYSFS_MOUNT_PATH "/sys"
|
||||
#define SYSFS_DEVICE_PATH SYSFS_MOUNT_PATH "/bus/usb/devices"
|
||||
|
||||
struct usbfs_ctrltransfer {
|
||||
/* keep in sync with usbdevice_fs.h:usbdevfs_ctrltransfer */
|
||||
__u8 bmRequestType;
|
||||
__u8 bRequest;
|
||||
__u16 wValue;
|
||||
__u16 wIndex;
|
||||
__u16 wLength;
|
||||
__u32 timeout; /* in milliseconds */
|
||||
|
||||
/* pointer to data */
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct usbfs_setinterface {
|
||||
/* keep in sync with usbdevice_fs.h:usbdevfs_setinterface */
|
||||
unsigned int interface;
|
||||
unsigned int altsetting;
|
||||
};
|
||||
|
||||
#define USBFS_MAXDRIVERNAME 255
|
||||
|
||||
struct usbfs_getdriver {
|
||||
unsigned int interface;
|
||||
char driver[USBFS_MAXDRIVERNAME + 1];
|
||||
};
|
||||
|
||||
#define USBFS_URB_SHORT_NOT_OK 0x01
|
||||
#define USBFS_URB_ISO_ASAP 0x02
|
||||
#define USBFS_URB_BULK_CONTINUATION 0x04
|
||||
#define USBFS_URB_QUEUE_BULK 0x10
|
||||
#define USBFS_URB_ZERO_PACKET 0x40
|
||||
|
||||
#define USBFS_URB_TYPE_ISO 0
|
||||
#define USBFS_URB_TYPE_INTERRUPT 1
|
||||
#define USBFS_URB_TYPE_CONTROL 2
|
||||
#define USBFS_URB_TYPE_BULK 3
|
||||
|
||||
struct usbfs_iso_packet_desc {
|
||||
unsigned int length;
|
||||
unsigned int actual_length;
|
||||
unsigned int status;
|
||||
};
|
||||
|
||||
#define MAX_BULK_BUFFER_LENGTH 16384
|
||||
#define MAX_CTRL_BUFFER_LENGTH 4096
|
||||
|
||||
#define MAX_ISO_PACKETS_PER_URB 128
|
||||
|
||||
struct usbfs_urb {
|
||||
unsigned char type;
|
||||
unsigned char endpoint;
|
||||
int status;
|
||||
unsigned int flags;
|
||||
void *buffer;
|
||||
int buffer_length;
|
||||
int actual_length;
|
||||
int start_frame;
|
||||
union {
|
||||
int number_of_packets; /* Only used for isoc urbs */
|
||||
unsigned int stream_id; /* Only used with bulk streams */
|
||||
};
|
||||
int error_count;
|
||||
unsigned int signr;
|
||||
void *usercontext;
|
||||
struct usbfs_iso_packet_desc iso_frame_desc[0];
|
||||
};
|
||||
|
||||
struct usbfs_connectinfo {
|
||||
unsigned int devnum;
|
||||
unsigned char slow;
|
||||
};
|
||||
|
||||
struct usbfs_ioctl {
|
||||
int ifno; /* interface 0..N ; negative numbers reserved */
|
||||
int ioctl_code; /* MUST encode size + direction of data so the
|
||||
* macros in <asm/ioctl.h> give correct values */
|
||||
void *data; /* param buffer (in, or out) */
|
||||
};
|
||||
|
||||
#define USBFS_CAP_ZERO_PACKET 0x01
|
||||
#define USBFS_CAP_BULK_CONTINUATION 0x02
|
||||
#define USBFS_CAP_NO_PACKET_SIZE_LIM 0x04
|
||||
#define USBFS_CAP_BULK_SCATTER_GATHER 0x08
|
||||
#define USBFS_CAP_REAP_AFTER_DISCONNECT 0x10
|
||||
|
||||
#define USBFS_DISCONNECT_CLAIM_IF_DRIVER 0x01
|
||||
#define USBFS_DISCONNECT_CLAIM_EXCEPT_DRIVER 0x02
|
||||
|
||||
struct usbfs_disconnect_claim {
|
||||
unsigned int interface;
|
||||
unsigned int flags;
|
||||
char driver[USBFS_MAXDRIVERNAME + 1];
|
||||
};
|
||||
|
||||
struct usbfs_streams {
|
||||
unsigned int num_streams; /* Not used by USBDEVFS_FREE_STREAMS */
|
||||
unsigned int num_eps;
|
||||
unsigned char eps[0];
|
||||
};
|
||||
|
||||
#define USBFS_SPEED_UNKNOWN 0
|
||||
#define USBFS_SPEED_LOW 1
|
||||
#define USBFS_SPEED_FULL 2
|
||||
#define USBFS_SPEED_HIGH 3
|
||||
#define USBFS_SPEED_WIRELESS 4
|
||||
#define USBFS_SPEED_SUPER 5
|
||||
#define USBFS_SPEED_SUPER_PLUS 6
|
||||
|
||||
#define IOCTL_USBFS_CONTROL _IOWR('U', 0, struct usbfs_ctrltransfer)
|
||||
#define IOCTL_USBFS_SETINTERFACE _IOR('U', 4, struct usbfs_setinterface)
|
||||
#define IOCTL_USBFS_SETCONFIGURATION _IOR('U', 5, unsigned int)
|
||||
#define IOCTL_USBFS_GETDRIVER _IOW('U', 8, struct usbfs_getdriver)
|
||||
#define IOCTL_USBFS_SUBMITURB _IOR('U', 10, struct usbfs_urb)
|
||||
#define IOCTL_USBFS_DISCARDURB _IO('U', 11)
|
||||
#define IOCTL_USBFS_REAPURBNDELAY _IOW('U', 13, void *)
|
||||
#define IOCTL_USBFS_CLAIMINTERFACE _IOR('U', 15, unsigned int)
|
||||
#define IOCTL_USBFS_RELEASEINTERFACE _IOR('U', 16, unsigned int)
|
||||
#define IOCTL_USBFS_CONNECTINFO _IOW('U', 17, struct usbfs_connectinfo)
|
||||
#define IOCTL_USBFS_IOCTL _IOWR('U', 18, struct usbfs_ioctl)
|
||||
#define IOCTL_USBFS_RESET _IO('U', 20)
|
||||
#define IOCTL_USBFS_CLEAR_HALT _IOR('U', 21, unsigned int)
|
||||
#define IOCTL_USBFS_DISCONNECT _IO('U', 22)
|
||||
#define IOCTL_USBFS_CONNECT _IO('U', 23)
|
||||
#define IOCTL_USBFS_GET_CAPABILITIES _IOR('U', 26, __u32)
|
||||
#define IOCTL_USBFS_DISCONNECT_CLAIM _IOR('U', 27, struct usbfs_disconnect_claim)
|
||||
#define IOCTL_USBFS_ALLOC_STREAMS _IOR('U', 28, struct usbfs_streams)
|
||||
#define IOCTL_USBFS_FREE_STREAMS _IOR('U', 29, struct usbfs_streams)
|
||||
#define IOCTL_USBFS_DROP_PRIVILEGES _IOW('U', 30, __u32)
|
||||
#define IOCTL_USBFS_GET_SPEED _IO('U', 31)
|
||||
|
||||
extern usbi_mutex_static_t linux_hotplug_lock;
|
||||
|
||||
#ifdef HAVE_LIBUDEV
|
||||
int linux_udev_start_event_monitor(void);
|
||||
int linux_udev_stop_event_monitor(void);
|
||||
int linux_udev_scan_devices(struct libusb_context *ctx);
|
||||
void linux_udev_hotplug_poll(void);
|
||||
#else
|
||||
int linux_netlink_start_event_monitor(void);
|
||||
int linux_netlink_stop_event_monitor(void);
|
||||
void linux_netlink_hotplug_poll(void);
|
||||
#endif
|
||||
|
||||
static inline int linux_start_event_monitor(void)
|
||||
{
|
||||
#if defined(HAVE_LIBUDEV)
|
||||
return linux_udev_start_event_monitor();
|
||||
/*
|
||||
* __ANDROID__: preprocessor macro defined automatically by GCC for all Android
|
||||
* targets (i.e. both Android native applications, and Android OS-level
|
||||
* services)
|
||||
*
|
||||
* ANDROID_OS: compilation flag that should be set for using libusb from programs
|
||||
* running on Android at OS level (e.g. Android platform services).
|
||||
* The programs using libusb built with the ANDROID_OS flag must have
|
||||
* permission to access netlink sockets.
|
||||
*/
|
||||
#elif !defined(__ANDROID__) || defined(ANDROID_OS)
|
||||
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__) || defined(ANDROID_OS)
|
||||
linux_netlink_stop_event_monitor();
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void linux_hotplug_poll(void)
|
||||
{
|
||||
#if defined(HAVE_LIBUDEV)
|
||||
linux_udev_hotplug_poll();
|
||||
#elif !defined(__ANDROID__) || defined(ANDROID_OS)
|
||||
linux_netlink_hotplug_poll();
|
||||
#endif
|
||||
}
|
||||
|
||||
void linux_hotplug_enumerate(uint8_t busnum, uint8_t devaddr, const char *sys_name);
|
||||
void linux_device_disconnected(uint8_t busnum, uint8_t devaddr);
|
||||
|
||||
int linux_get_device_address(struct libusb_context *ctx, int detached,
|
||||
uint8_t *busnum, uint8_t *devaddr, const char *dev_node,
|
||||
const char *sys_name, int fd);
|
||||
int linux_enumerate_device(struct libusb_context *ctx,
|
||||
uint8_t busnum, uint8_t devaddr, const char *sysfs_dir);
|
||||
|
||||
#endif
|
||||
617
lib/libusb/libusb/os/netbsd_usb.c
Normal file
617
lib/libusb/libusb/os/netbsd_usb.c
Normal file
@@ -0,0 +1,617 @@
|
||||
/*
|
||||
* Copyright © 2011 Martin Pieuchot <mpi@openbsd.org>
|
||||
*
|
||||
* 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 <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
|
||||
#include "libusbi.h"
|
||||
|
||||
struct device_priv {
|
||||
char devnode[16];
|
||||
int fd;
|
||||
|
||||
usb_config_descriptor_t *cdesc; /* active config descriptor */
|
||||
};
|
||||
|
||||
struct handle_priv {
|
||||
int endpoints[USB_MAX_ENDPOINTS];
|
||||
};
|
||||
|
||||
/*
|
||||
* Backend functions
|
||||
*/
|
||||
static int netbsd_get_device_list(struct libusb_context *,
|
||||
struct discovered_devs **);
|
||||
static int netbsd_open(struct libusb_device_handle *);
|
||||
static void netbsd_close(struct libusb_device_handle *);
|
||||
|
||||
static int netbsd_get_active_config_descriptor(struct libusb_device *,
|
||||
void *, size_t);
|
||||
static int netbsd_get_config_descriptor(struct libusb_device *, uint8_t,
|
||||
void *, size_t);
|
||||
|
||||
static int netbsd_get_configuration(struct libusb_device_handle *, uint8_t *);
|
||||
static int netbsd_set_configuration(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 *, uint8_t);
|
||||
|
||||
static int netbsd_set_interface_altsetting(struct libusb_device_handle *,
|
||||
uint8_t, uint8_t);
|
||||
static int netbsd_clear_halt(struct libusb_device_handle *, unsigned char);
|
||||
static void netbsd_destroy_device(struct libusb_device *);
|
||||
|
||||
static int netbsd_submit_transfer(struct usbi_transfer *);
|
||||
static int netbsd_cancel_transfer(struct usbi_transfer *);
|
||||
static int netbsd_handle_transfer_completion(struct usbi_transfer *);
|
||||
|
||||
/*
|
||||
* Private functions
|
||||
*/
|
||||
static int _errno_to_libusb(int);
|
||||
static int _cache_active_config_descriptor(struct libusb_device *, int);
|
||||
static int _sync_control_transfer(struct usbi_transfer *);
|
||||
static int _sync_gen_transfer(struct usbi_transfer *);
|
||||
static int _access_endpoint(struct libusb_transfer *);
|
||||
|
||||
const struct usbi_os_backend usbi_backend = {
|
||||
.name = "Synchronous NetBSD backend",
|
||||
.caps = 0,
|
||||
.get_device_list = netbsd_get_device_list,
|
||||
.open = netbsd_open,
|
||||
.close = netbsd_close,
|
||||
|
||||
.get_active_config_descriptor = netbsd_get_active_config_descriptor,
|
||||
.get_config_descriptor = netbsd_get_config_descriptor,
|
||||
|
||||
.get_configuration = netbsd_get_configuration,
|
||||
.set_configuration = netbsd_set_configuration,
|
||||
|
||||
.claim_interface = netbsd_claim_interface,
|
||||
.release_interface = netbsd_release_interface,
|
||||
|
||||
.set_interface_altsetting = netbsd_set_interface_altsetting,
|
||||
.clear_halt = netbsd_clear_halt,
|
||||
|
||||
.destroy_device = netbsd_destroy_device,
|
||||
|
||||
.submit_transfer = netbsd_submit_transfer,
|
||||
.cancel_transfer = netbsd_cancel_transfer,
|
||||
|
||||
.handle_transfer_completion = netbsd_handle_transfer_completion,
|
||||
|
||||
.device_priv_size = sizeof(struct device_priv),
|
||||
.device_handle_priv_size = sizeof(struct handle_priv),
|
||||
};
|
||||
|
||||
int
|
||||
netbsd_get_device_list(struct libusb_context * ctx,
|
||||
struct discovered_devs **discdevs)
|
||||
{
|
||||
struct libusb_device *dev;
|
||||
struct device_priv *dpriv;
|
||||
struct usb_device_info di;
|
||||
usb_device_descriptor_t ddesc;
|
||||
unsigned long session_id;
|
||||
char devnode[16];
|
||||
int fd, err, i;
|
||||
|
||||
usbi_dbg(ctx, " ");
|
||||
|
||||
/* Only ugen(4) is supported */
|
||||
for (i = 0; i < USB_MAX_DEVICES; i++) {
|
||||
/* Control endpoint is always .00 */
|
||||
snprintf(devnode, sizeof(devnode), "/dev/ugen%d.00", i);
|
||||
|
||||
if ((fd = open(devnode, O_RDONLY)) < 0) {
|
||||
if (errno != ENOENT && errno != ENXIO)
|
||||
usbi_err(ctx, "could not open %s", devnode);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ioctl(fd, USB_GET_DEVICEINFO, &di) < 0)
|
||||
continue;
|
||||
|
||||
session_id = (di.udi_bus << 8 | di.udi_addr);
|
||||
dev = usbi_get_device_by_session_id(ctx, session_id);
|
||||
|
||||
if (dev == NULL) {
|
||||
dev = usbi_alloc_device(ctx, session_id);
|
||||
if (dev == NULL)
|
||||
return LIBUSB_ERROR_NO_MEM;
|
||||
|
||||
dev->bus_number = 1 + di.udi_bus;
|
||||
dev->device_address = 1 + di.udi_addr;
|
||||
dev->speed = di.udi_speed; /* NetBSD #define's happen to match libusb enum */
|
||||
|
||||
dpriv = usbi_get_device_priv(dev);
|
||||
strlcpy(dpriv->devnode, devnode, sizeof(devnode));
|
||||
dpriv->fd = -1;
|
||||
|
||||
if (ioctl(fd, USB_GET_DEVICE_DESC, &ddesc) < 0) {
|
||||
err = errno;
|
||||
goto error;
|
||||
}
|
||||
|
||||
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)) {
|
||||
err = errno;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((err = usbi_sanitize_device(dev)))
|
||||
goto error;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
if (discovered_devs_append(*discdevs, dev) == NULL)
|
||||
return LIBUSB_ERROR_NO_MEM;
|
||||
|
||||
libusb_unref_device(dev);
|
||||
}
|
||||
|
||||
return LIBUSB_SUCCESS;
|
||||
|
||||
error:
|
||||
close(fd);
|
||||
libusb_unref_device(dev);
|
||||
return _errno_to_libusb(err);
|
||||
}
|
||||
|
||||
int
|
||||
netbsd_open(struct libusb_device_handle *handle)
|
||||
{
|
||||
struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
|
||||
struct handle_priv *hpriv = usbi_get_device_handle_priv(handle);
|
||||
int i;
|
||||
|
||||
dpriv->fd = open(dpriv->devnode, O_RDWR);
|
||||
if (dpriv->fd < 0) {
|
||||
dpriv->fd = open(dpriv->devnode, O_RDONLY);
|
||||
if (dpriv->fd < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
}
|
||||
|
||||
for (i = 0; i < USB_MAX_ENDPOINTS; i++)
|
||||
hpriv->endpoints[i] = -1;
|
||||
|
||||
usbi_dbg(HANDLE_CTX(handle), "open %s: fd %d", dpriv->devnode, dpriv->fd);
|
||||
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
netbsd_close(struct libusb_device_handle *handle)
|
||||
{
|
||||
struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
|
||||
|
||||
usbi_dbg(HANDLE_CTX(handle), "close: fd %d", dpriv->fd);
|
||||
|
||||
close(dpriv->fd);
|
||||
dpriv->fd = -1;
|
||||
}
|
||||
|
||||
int
|
||||
netbsd_get_active_config_descriptor(struct libusb_device *dev,
|
||||
void *buf, size_t len)
|
||||
{
|
||||
struct device_priv *dpriv = usbi_get_device_priv(dev);
|
||||
|
||||
len = MIN(len, (size_t)UGETW(dpriv->cdesc->wTotalLength));
|
||||
|
||||
usbi_dbg(DEVICE_CTX(dev), "len %zu", len);
|
||||
|
||||
memcpy(buf, dpriv->cdesc, len);
|
||||
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
int
|
||||
netbsd_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
|
||||
void *buf, size_t len)
|
||||
{
|
||||
struct device_priv *dpriv = usbi_get_device_priv(dev);
|
||||
struct usb_full_desc ufd;
|
||||
int fd, err;
|
||||
|
||||
usbi_dbg(DEVICE_CTX(dev), "index %u, len %zu", idx, len);
|
||||
|
||||
/* A config descriptor may be requested before opening the device */
|
||||
if (dpriv->fd >= 0) {
|
||||
fd = dpriv->fd;
|
||||
} else {
|
||||
fd = open(dpriv->devnode, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
}
|
||||
|
||||
ufd.ufd_config_index = idx;
|
||||
ufd.ufd_size = len;
|
||||
ufd.ufd_data = buf;
|
||||
|
||||
if (ioctl(fd, USB_GET_FULL_DESC, &ufd) < 0) {
|
||||
err = errno;
|
||||
if (dpriv->fd < 0)
|
||||
close(fd);
|
||||
return _errno_to_libusb(err);
|
||||
}
|
||||
|
||||
if (dpriv->fd < 0)
|
||||
close(fd);
|
||||
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
int
|
||||
netbsd_get_configuration(struct libusb_device_handle *handle, uint8_t *config)
|
||||
{
|
||||
struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
|
||||
int tmp;
|
||||
|
||||
usbi_dbg(HANDLE_CTX(handle), " ");
|
||||
|
||||
if (ioctl(dpriv->fd, USB_GET_CONFIG, &tmp) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
usbi_dbg(HANDLE_CTX(handle), "configuration %d", tmp);
|
||||
*config = (uint8_t)tmp;
|
||||
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
netbsd_set_configuration(struct libusb_device_handle *handle, int config)
|
||||
{
|
||||
struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
|
||||
|
||||
usbi_dbg(HANDLE_CTX(handle), "configuration %d", config);
|
||||
|
||||
if (ioctl(dpriv->fd, USB_SET_CONFIG, &config) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
return _cache_active_config_descriptor(handle->dev, dpriv->fd);
|
||||
}
|
||||
|
||||
int
|
||||
netbsd_claim_interface(struct libusb_device_handle *handle, uint8_t iface)
|
||||
{
|
||||
struct handle_priv *hpriv = usbi_get_device_handle_priv(handle);
|
||||
int i;
|
||||
|
||||
UNUSED(iface);
|
||||
|
||||
for (i = 0; i < USB_MAX_ENDPOINTS; i++)
|
||||
hpriv->endpoints[i] = -1;
|
||||
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
netbsd_release_interface(struct libusb_device_handle *handle, uint8_t iface)
|
||||
{
|
||||
struct handle_priv *hpriv = usbi_get_device_handle_priv(handle);
|
||||
int i;
|
||||
|
||||
UNUSED(iface);
|
||||
|
||||
for (i = 0; i < USB_MAX_ENDPOINTS; i++)
|
||||
if (hpriv->endpoints[i] >= 0)
|
||||
close(hpriv->endpoints[i]);
|
||||
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
netbsd_set_interface_altsetting(struct libusb_device_handle *handle, uint8_t iface,
|
||||
uint8_t altsetting)
|
||||
{
|
||||
struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
|
||||
struct usb_alt_interface intf;
|
||||
|
||||
usbi_dbg(HANDLE_CTX(handle), "iface %u, setting %u", iface, altsetting);
|
||||
|
||||
memset(&intf, 0, sizeof(intf));
|
||||
|
||||
intf.uai_interface_index = iface;
|
||||
intf.uai_alt_no = altsetting;
|
||||
|
||||
if (ioctl(dpriv->fd, USB_SET_ALTINTERFACE, &intf) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
netbsd_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint)
|
||||
{
|
||||
struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
|
||||
struct usb_ctl_request req;
|
||||
|
||||
usbi_dbg(HANDLE_CTX(handle), " ");
|
||||
|
||||
req.ucr_request.bmRequestType = UT_WRITE_ENDPOINT;
|
||||
req.ucr_request.bRequest = UR_CLEAR_FEATURE;
|
||||
USETW(req.ucr_request.wValue, UF_ENDPOINT_HALT);
|
||||
USETW(req.ucr_request.wIndex, endpoint);
|
||||
USETW(req.ucr_request.wLength, 0);
|
||||
|
||||
if (ioctl(dpriv->fd, USB_DO_REQUEST, &req) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
netbsd_destroy_device(struct libusb_device *dev)
|
||||
{
|
||||
struct device_priv *dpriv = usbi_get_device_priv(dev);
|
||||
|
||||
usbi_dbg(DEVICE_CTX(dev), " ");
|
||||
|
||||
free(dpriv->cdesc);
|
||||
}
|
||||
|
||||
int
|
||||
netbsd_submit_transfer(struct usbi_transfer *itransfer)
|
||||
{
|
||||
struct libusb_transfer *transfer;
|
||||
int err = 0;
|
||||
|
||||
usbi_dbg(ITRANSFER_CTX(itransfer), " ");
|
||||
|
||||
transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
||||
|
||||
switch (transfer->type) {
|
||||
case LIBUSB_TRANSFER_TYPE_CONTROL:
|
||||
err = _sync_control_transfer(itransfer);
|
||||
break;
|
||||
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
|
||||
if (IS_XFEROUT(transfer)) {
|
||||
/* Isochronous write is not supported */
|
||||
err = LIBUSB_ERROR_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
err = _sync_gen_transfer(itransfer);
|
||||
break;
|
||||
case LIBUSB_TRANSFER_TYPE_BULK:
|
||||
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
|
||||
if (IS_XFEROUT(transfer) &&
|
||||
transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) {
|
||||
err = LIBUSB_ERROR_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
err = _sync_gen_transfer(itransfer);
|
||||
break;
|
||||
case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
|
||||
err = LIBUSB_ERROR_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
usbi_signal_transfer_completion(itransfer);
|
||||
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
netbsd_cancel_transfer(struct usbi_transfer *itransfer)
|
||||
{
|
||||
UNUSED(itransfer);
|
||||
|
||||
usbi_dbg(ITRANSFER_CTX(itransfer), " ");
|
||||
|
||||
return LIBUSB_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
int
|
||||
netbsd_handle_transfer_completion(struct usbi_transfer *itransfer)
|
||||
{
|
||||
return usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_COMPLETED);
|
||||
}
|
||||
|
||||
int
|
||||
_errno_to_libusb(int err)
|
||||
{
|
||||
usbi_dbg(NULL, "error: %s (%d)", strerror(err), err);
|
||||
|
||||
switch (err) {
|
||||
case EIO:
|
||||
return LIBUSB_ERROR_IO;
|
||||
case EACCES:
|
||||
return LIBUSB_ERROR_ACCESS;
|
||||
case ENOENT:
|
||||
return LIBUSB_ERROR_NO_DEVICE;
|
||||
case ENOMEM:
|
||||
return LIBUSB_ERROR_NO_MEM;
|
||||
case EWOULDBLOCK:
|
||||
case ETIMEDOUT:
|
||||
return LIBUSB_ERROR_TIMEOUT;
|
||||
default:
|
||||
return LIBUSB_ERROR_OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
_cache_active_config_descriptor(struct libusb_device *dev, int fd)
|
||||
{
|
||||
struct device_priv *dpriv = usbi_get_device_priv(dev);
|
||||
struct usb_config_desc ucd;
|
||||
struct usb_full_desc ufd;
|
||||
void *buf;
|
||||
int len;
|
||||
|
||||
usbi_dbg(DEVICE_CTX(dev), "fd %d", fd);
|
||||
|
||||
ucd.ucd_config_index = USB_CURRENT_CONFIG_INDEX;
|
||||
|
||||
if (ioctl(fd, USB_GET_CONFIG_DESC, &ucd) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
usbi_dbg(DEVICE_CTX(dev), "active bLength %d", ucd.ucd_desc.bLength);
|
||||
|
||||
len = UGETW(ucd.ucd_desc.wTotalLength);
|
||||
buf = malloc((size_t)len);
|
||||
if (buf == NULL)
|
||||
return LIBUSB_ERROR_NO_MEM;
|
||||
|
||||
ufd.ufd_config_index = ucd.ucd_config_index;
|
||||
ufd.ufd_size = len;
|
||||
ufd.ufd_data = buf;
|
||||
|
||||
usbi_dbg(DEVICE_CTX(dev), "index %d, len %d", ufd.ufd_config_index, len);
|
||||
|
||||
if (ioctl(fd, USB_GET_FULL_DESC, &ufd) < 0) {
|
||||
free(buf);
|
||||
return _errno_to_libusb(errno);
|
||||
}
|
||||
|
||||
if (dpriv->cdesc)
|
||||
free(dpriv->cdesc);
|
||||
dpriv->cdesc = buf;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_sync_control_transfer(struct usbi_transfer *itransfer)
|
||||
{
|
||||
struct libusb_transfer *transfer;
|
||||
struct libusb_control_setup *setup;
|
||||
struct device_priv *dpriv;
|
||||
struct usb_ctl_request req;
|
||||
|
||||
transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
||||
dpriv = usbi_get_device_priv(transfer->dev_handle->dev);
|
||||
setup = (struct libusb_control_setup *)transfer->buffer;
|
||||
|
||||
usbi_dbg(ITRANSFER_CTX(itransfer), "type 0x%x request 0x%x value 0x%x index %d length %d timeout %d",
|
||||
setup->bmRequestType, setup->bRequest,
|
||||
libusb_le16_to_cpu(setup->wValue),
|
||||
libusb_le16_to_cpu(setup->wIndex),
|
||||
libusb_le16_to_cpu(setup->wLength), transfer->timeout);
|
||||
|
||||
req.ucr_request.bmRequestType = setup->bmRequestType;
|
||||
req.ucr_request.bRequest = setup->bRequest;
|
||||
/* Don't use USETW, libusb already deals with the endianness */
|
||||
(*(uint16_t *)req.ucr_request.wValue) = setup->wValue;
|
||||
(*(uint16_t *)req.ucr_request.wIndex) = setup->wIndex;
|
||||
(*(uint16_t *)req.ucr_request.wLength) = setup->wLength;
|
||||
req.ucr_data = transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
|
||||
|
||||
if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
|
||||
req.ucr_flags = USBD_SHORT_XFER_OK;
|
||||
|
||||
if (ioctl(dpriv->fd, USB_SET_TIMEOUT, &transfer->timeout) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
if (ioctl(dpriv->fd, USB_DO_REQUEST, &req) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
itransfer->transferred = req.ucr_actlen;
|
||||
|
||||
usbi_dbg(ITRANSFER_CTX(itransfer), "transferred %d", itransfer->transferred);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_access_endpoint(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct handle_priv *hpriv;
|
||||
struct device_priv *dpriv;
|
||||
char *s, devnode[16];
|
||||
int fd, endpt;
|
||||
mode_t mode;
|
||||
|
||||
hpriv = usbi_get_device_handle_priv(transfer->dev_handle);
|
||||
dpriv = usbi_get_device_priv(transfer->dev_handle->dev);
|
||||
|
||||
endpt = UE_GET_ADDR(transfer->endpoint);
|
||||
mode = IS_XFERIN(transfer) ? O_RDONLY : O_WRONLY;
|
||||
|
||||
usbi_dbg(TRANSFER_CTX(transfer), "endpoint %d mode %d", endpt, mode);
|
||||
|
||||
if (hpriv->endpoints[endpt] < 0) {
|
||||
/* Pick the right node given the control one */
|
||||
strlcpy(devnode, dpriv->devnode, sizeof(devnode));
|
||||
s = strchr(devnode, '.');
|
||||
snprintf(s, 4, ".%02d", endpt);
|
||||
|
||||
/* We may need to read/write to the same endpoint later. */
|
||||
if (((fd = open(devnode, O_RDWR)) < 0) && (errno == ENXIO))
|
||||
if ((fd = open(devnode, mode)) < 0)
|
||||
return -1;
|
||||
|
||||
hpriv->endpoints[endpt] = fd;
|
||||
}
|
||||
|
||||
return hpriv->endpoints[endpt];
|
||||
}
|
||||
|
||||
int
|
||||
_sync_gen_transfer(struct usbi_transfer *itransfer)
|
||||
{
|
||||
struct libusb_transfer *transfer;
|
||||
int fd, nr = 1;
|
||||
|
||||
transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
||||
|
||||
/*
|
||||
* Bulk, Interrupt or Isochronous transfer depends on the
|
||||
* endpoint and thus the node to open.
|
||||
*/
|
||||
if ((fd = _access_endpoint(transfer)) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
if (ioctl(fd, USB_SET_TIMEOUT, &transfer->timeout) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
if (IS_XFERIN(transfer)) {
|
||||
if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
|
||||
if (ioctl(fd, USB_SET_SHORT_XFER, &nr) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
nr = read(fd, transfer->buffer, transfer->length);
|
||||
} else {
|
||||
nr = write(fd, transfer->buffer, transfer->length);
|
||||
}
|
||||
|
||||
if (nr < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
itransfer->transferred = nr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
111
lib/libusb/libusb/os/null_usb.c
Normal file
111
lib/libusb/libusb/os/null_usb.c
Normal 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,
|
||||
};
|
||||
700
lib/libusb/libusb/os/openbsd_usb.c
Normal file
700
lib/libusb/libusb/os/openbsd_usb.c
Normal file
@@ -0,0 +1,700 @@
|
||||
/*
|
||||
* Copyright © 2011-2013 Martin Pieuchot <mpi@openbsd.org>
|
||||
*
|
||||
* 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 <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
|
||||
#include "libusbi.h"
|
||||
|
||||
struct device_priv {
|
||||
char *devname; /* name of the ugen(4) node */
|
||||
int fd; /* device file descriptor */
|
||||
|
||||
usb_config_descriptor_t *cdesc; /* active config descriptor */
|
||||
};
|
||||
|
||||
struct handle_priv {
|
||||
int endpoints[USB_MAX_ENDPOINTS];
|
||||
};
|
||||
|
||||
/*
|
||||
* Backend functions
|
||||
*/
|
||||
static int obsd_get_device_list(struct libusb_context *,
|
||||
struct discovered_devs **);
|
||||
static int obsd_open(struct libusb_device_handle *);
|
||||
static void obsd_close(struct libusb_device_handle *);
|
||||
|
||||
static int obsd_get_active_config_descriptor(struct libusb_device *,
|
||||
void *, size_t);
|
||||
static int obsd_get_config_descriptor(struct libusb_device *, uint8_t,
|
||||
void *, size_t);
|
||||
|
||||
static int obsd_get_configuration(struct libusb_device_handle *, uint8_t *);
|
||||
static int obsd_set_configuration(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 *, uint8_t);
|
||||
|
||||
static int obsd_set_interface_altsetting(struct libusb_device_handle *, uint8_t,
|
||||
uint8_t);
|
||||
static int obsd_clear_halt(struct libusb_device_handle *, unsigned char);
|
||||
static void obsd_destroy_device(struct libusb_device *);
|
||||
|
||||
static int obsd_submit_transfer(struct usbi_transfer *);
|
||||
static int obsd_cancel_transfer(struct usbi_transfer *);
|
||||
static int obsd_handle_transfer_completion(struct usbi_transfer *);
|
||||
|
||||
/*
|
||||
* Private functions
|
||||
*/
|
||||
static int _errno_to_libusb(int);
|
||||
static int _cache_active_config_descriptor(struct libusb_device *);
|
||||
static int _sync_control_transfer(struct usbi_transfer *);
|
||||
static int _sync_gen_transfer(struct usbi_transfer *);
|
||||
static int _access_endpoint(struct libusb_transfer *);
|
||||
|
||||
static int _bus_open(int);
|
||||
|
||||
|
||||
const struct usbi_os_backend usbi_backend = {
|
||||
.name = "Synchronous OpenBSD backend",
|
||||
.get_device_list = obsd_get_device_list,
|
||||
.open = obsd_open,
|
||||
.close = obsd_close,
|
||||
|
||||
.get_active_config_descriptor = obsd_get_active_config_descriptor,
|
||||
.get_config_descriptor = obsd_get_config_descriptor,
|
||||
|
||||
.get_configuration = obsd_get_configuration,
|
||||
.set_configuration = obsd_set_configuration,
|
||||
|
||||
.claim_interface = obsd_claim_interface,
|
||||
.release_interface = obsd_release_interface,
|
||||
|
||||
.set_interface_altsetting = obsd_set_interface_altsetting,
|
||||
.clear_halt = obsd_clear_halt,
|
||||
.destroy_device = obsd_destroy_device,
|
||||
|
||||
.submit_transfer = obsd_submit_transfer,
|
||||
.cancel_transfer = obsd_cancel_transfer,
|
||||
|
||||
.handle_transfer_completion = obsd_handle_transfer_completion,
|
||||
|
||||
.device_priv_size = sizeof(struct device_priv),
|
||||
.device_handle_priv_size = sizeof(struct handle_priv),
|
||||
};
|
||||
|
||||
#define DEVPATH "/dev/"
|
||||
#define USBDEV DEVPATH "usb"
|
||||
|
||||
int
|
||||
obsd_get_device_list(struct libusb_context * ctx,
|
||||
struct discovered_devs **discdevs)
|
||||
{
|
||||
struct discovered_devs *ddd;
|
||||
struct libusb_device *dev;
|
||||
struct device_priv *dpriv;
|
||||
struct usb_device_info di;
|
||||
struct usb_device_ddesc dd;
|
||||
unsigned long session_id;
|
||||
char devices[USB_MAX_DEVICES];
|
||||
char busnode[16];
|
||||
char *udevname;
|
||||
int fd, addr, i, j;
|
||||
|
||||
usbi_dbg(ctx, " ");
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
snprintf(busnode, sizeof(busnode), USBDEV "%d", i);
|
||||
|
||||
if ((fd = open(busnode, O_RDWR)) < 0) {
|
||||
if (errno != ENOENT && errno != ENXIO)
|
||||
usbi_err(ctx, "could not open %s", busnode);
|
||||
continue;
|
||||
}
|
||||
|
||||
bzero(devices, sizeof(devices));
|
||||
for (addr = 1; addr < USB_MAX_DEVICES; addr++) {
|
||||
if (devices[addr])
|
||||
continue;
|
||||
|
||||
di.udi_addr = addr;
|
||||
if (ioctl(fd, USB_DEVICEINFO, &di) < 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* XXX If ugen(4) is attached to the USB device
|
||||
* it will be used.
|
||||
*/
|
||||
udevname = NULL;
|
||||
for (j = 0; j < USB_MAX_DEVNAMES; j++)
|
||||
if (!strncmp("ugen", di.udi_devnames[j], 4)) {
|
||||
udevname = strdup(di.udi_devnames[j]);
|
||||
break;
|
||||
}
|
||||
|
||||
session_id = (di.udi_bus << 8 | di.udi_addr);
|
||||
dev = usbi_get_device_by_session_id(ctx, session_id);
|
||||
|
||||
if (dev == NULL) {
|
||||
dev = usbi_alloc_device(ctx, session_id);
|
||||
if (dev == NULL) {
|
||||
close(fd);
|
||||
return LIBUSB_ERROR_NO_MEM;
|
||||
}
|
||||
|
||||
dev->bus_number = di.udi_bus;
|
||||
dev->device_address = di.udi_addr;
|
||||
dev->speed = di.udi_speed;
|
||||
dev->port_number = di.udi_port;
|
||||
|
||||
dpriv = usbi_get_device_priv(dev);
|
||||
dpriv->fd = -1;
|
||||
dpriv->devname = udevname;
|
||||
|
||||
dd.udd_bus = di.udi_bus;
|
||||
dd.udd_addr = di.udi_addr;
|
||||
if (ioctl(fd, USB_DEVICE_GET_DDESC, &dd) < 0) {
|
||||
libusb_unref_device(dev);
|
||||
continue;
|
||||
}
|
||||
|
||||
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)) {
|
||||
libusb_unref_device(dev);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (usbi_sanitize_device(dev)) {
|
||||
libusb_unref_device(dev);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ddd = discovered_devs_append(*discdevs, dev);
|
||||
if (ddd == NULL) {
|
||||
close(fd);
|
||||
return LIBUSB_ERROR_NO_MEM;
|
||||
}
|
||||
libusb_unref_device(dev);
|
||||
|
||||
*discdevs = ddd;
|
||||
devices[addr] = 1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
obsd_open(struct libusb_device_handle *handle)
|
||||
{
|
||||
struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
|
||||
char devnode[16];
|
||||
|
||||
if (dpriv->devname) {
|
||||
int fd;
|
||||
/*
|
||||
* Only open ugen(4) attached devices read-write, all
|
||||
* read-only operations are done through the bus node.
|
||||
*/
|
||||
snprintf(devnode, sizeof(devnode), DEVPATH "%s.00",
|
||||
dpriv->devname);
|
||||
fd = open(devnode, O_RDWR);
|
||||
if (fd < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
dpriv->fd = fd;
|
||||
|
||||
usbi_dbg(HANDLE_CTX(handle), "open %s: fd %d", devnode, dpriv->fd);
|
||||
}
|
||||
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
obsd_close(struct libusb_device_handle *handle)
|
||||
{
|
||||
struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
|
||||
|
||||
if (dpriv->devname) {
|
||||
usbi_dbg(HANDLE_CTX(handle), "close: fd %d", dpriv->fd);
|
||||
|
||||
close(dpriv->fd);
|
||||
dpriv->fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
obsd_get_active_config_descriptor(struct libusb_device *dev,
|
||||
void *buf, size_t len)
|
||||
{
|
||||
struct device_priv *dpriv = usbi_get_device_priv(dev);
|
||||
|
||||
len = MIN(len, (size_t)UGETW(dpriv->cdesc->wTotalLength));
|
||||
|
||||
usbi_dbg(DEVICE_CTX(dev), "len %zu", len);
|
||||
|
||||
memcpy(buf, dpriv->cdesc, len);
|
||||
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
int
|
||||
obsd_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
|
||||
void *buf, size_t len)
|
||||
{
|
||||
struct usb_device_fdesc udf;
|
||||
int fd, err;
|
||||
|
||||
if ((fd = _bus_open(dev->bus_number)) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
udf.udf_bus = dev->bus_number;
|
||||
udf.udf_addr = dev->device_address;
|
||||
udf.udf_config_index = idx;
|
||||
udf.udf_size = len;
|
||||
udf.udf_data = buf;
|
||||
|
||||
usbi_dbg(DEVICE_CTX(dev), "index %d, len %zu", udf.udf_config_index, len);
|
||||
|
||||
if (ioctl(fd, USB_DEVICE_GET_FDESC, &udf) < 0) {
|
||||
err = errno;
|
||||
close(fd);
|
||||
return _errno_to_libusb(err);
|
||||
}
|
||||
close(fd);
|
||||
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
int
|
||||
obsd_get_configuration(struct libusb_device_handle *handle, uint8_t *config)
|
||||
{
|
||||
struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
|
||||
|
||||
*config = dpriv->cdesc->bConfigurationValue;
|
||||
|
||||
usbi_dbg(HANDLE_CTX(handle), "bConfigurationValue %u", *config);
|
||||
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
obsd_set_configuration(struct libusb_device_handle *handle, int config)
|
||||
{
|
||||
struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
|
||||
|
||||
if (dpriv->devname == NULL)
|
||||
return LIBUSB_ERROR_NOT_SUPPORTED;
|
||||
|
||||
usbi_dbg(HANDLE_CTX(handle), "bConfigurationValue %d", config);
|
||||
|
||||
if (ioctl(dpriv->fd, USB_SET_CONFIG, &config) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
return _cache_active_config_descriptor(handle->dev);
|
||||
}
|
||||
|
||||
int
|
||||
obsd_claim_interface(struct libusb_device_handle *handle, uint8_t iface)
|
||||
{
|
||||
struct handle_priv *hpriv = usbi_get_device_handle_priv(handle);
|
||||
int i;
|
||||
|
||||
UNUSED(iface);
|
||||
|
||||
for (i = 0; i < USB_MAX_ENDPOINTS; i++)
|
||||
hpriv->endpoints[i] = -1;
|
||||
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
obsd_release_interface(struct libusb_device_handle *handle, uint8_t iface)
|
||||
{
|
||||
struct handle_priv *hpriv = usbi_get_device_handle_priv(handle);
|
||||
int i;
|
||||
|
||||
UNUSED(iface);
|
||||
|
||||
for (i = 0; i < USB_MAX_ENDPOINTS; i++)
|
||||
if (hpriv->endpoints[i] >= 0)
|
||||
close(hpriv->endpoints[i]);
|
||||
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
obsd_set_interface_altsetting(struct libusb_device_handle *handle, uint8_t iface,
|
||||
uint8_t altsetting)
|
||||
{
|
||||
struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
|
||||
struct usb_alt_interface intf;
|
||||
|
||||
if (dpriv->devname == NULL)
|
||||
return LIBUSB_ERROR_NOT_SUPPORTED;
|
||||
|
||||
usbi_dbg(HANDLE_CTX(handle), "iface %u, setting %u", iface, altsetting);
|
||||
|
||||
memset(&intf, 0, sizeof(intf));
|
||||
|
||||
intf.uai_interface_index = iface;
|
||||
intf.uai_alt_no = altsetting;
|
||||
|
||||
if (ioctl(dpriv->fd, USB_SET_ALTINTERFACE, &intf) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
obsd_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint)
|
||||
{
|
||||
struct usb_ctl_request req;
|
||||
int fd, err;
|
||||
|
||||
if ((fd = _bus_open(handle->dev->bus_number)) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
usbi_dbg(HANDLE_CTX(handle), " ");
|
||||
|
||||
req.ucr_addr = handle->dev->device_address;
|
||||
req.ucr_request.bmRequestType = UT_WRITE_ENDPOINT;
|
||||
req.ucr_request.bRequest = UR_CLEAR_FEATURE;
|
||||
USETW(req.ucr_request.wValue, UF_ENDPOINT_HALT);
|
||||
USETW(req.ucr_request.wIndex, endpoint);
|
||||
USETW(req.ucr_request.wLength, 0);
|
||||
|
||||
if (ioctl(fd, USB_REQUEST, &req) < 0) {
|
||||
err = errno;
|
||||
close(fd);
|
||||
return _errno_to_libusb(err);
|
||||
}
|
||||
close(fd);
|
||||
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
obsd_destroy_device(struct libusb_device *dev)
|
||||
{
|
||||
struct device_priv *dpriv = usbi_get_device_priv(dev);
|
||||
|
||||
usbi_dbg(DEVICE_CTX(dev), " ");
|
||||
|
||||
free(dpriv->cdesc);
|
||||
free(dpriv->devname);
|
||||
}
|
||||
|
||||
int
|
||||
obsd_submit_transfer(struct usbi_transfer *itransfer)
|
||||
{
|
||||
struct libusb_transfer *transfer;
|
||||
int err = 0;
|
||||
|
||||
usbi_dbg(ITRANSFER_CTX(itransfer), " ");
|
||||
|
||||
transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
||||
|
||||
switch (transfer->type) {
|
||||
case LIBUSB_TRANSFER_TYPE_CONTROL:
|
||||
err = _sync_control_transfer(itransfer);
|
||||
break;
|
||||
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
|
||||
if (IS_XFEROUT(transfer)) {
|
||||
/* Isochronous write is not supported */
|
||||
err = LIBUSB_ERROR_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
err = _sync_gen_transfer(itransfer);
|
||||
break;
|
||||
case LIBUSB_TRANSFER_TYPE_BULK:
|
||||
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
|
||||
if (IS_XFEROUT(transfer) &&
|
||||
transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) {
|
||||
err = LIBUSB_ERROR_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
err = _sync_gen_transfer(itransfer);
|
||||
break;
|
||||
case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
|
||||
err = LIBUSB_ERROR_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
usbi_signal_transfer_completion(itransfer);
|
||||
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
obsd_cancel_transfer(struct usbi_transfer *itransfer)
|
||||
{
|
||||
UNUSED(itransfer);
|
||||
|
||||
usbi_dbg(ITRANSFER_CTX(itransfer), " ");
|
||||
|
||||
return LIBUSB_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
int
|
||||
obsd_handle_transfer_completion(struct usbi_transfer *itransfer)
|
||||
{
|
||||
return usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_COMPLETED);
|
||||
}
|
||||
|
||||
int
|
||||
_errno_to_libusb(int err)
|
||||
{
|
||||
usbi_dbg(NULL, "error: %s (%d)", strerror(err), err);
|
||||
|
||||
switch (err) {
|
||||
case EIO:
|
||||
return LIBUSB_ERROR_IO;
|
||||
case EACCES:
|
||||
return LIBUSB_ERROR_ACCESS;
|
||||
case ENOENT:
|
||||
return LIBUSB_ERROR_NO_DEVICE;
|
||||
case ENOMEM:
|
||||
return LIBUSB_ERROR_NO_MEM;
|
||||
case ETIMEDOUT:
|
||||
return LIBUSB_ERROR_TIMEOUT;
|
||||
default:
|
||||
return LIBUSB_ERROR_OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
_cache_active_config_descriptor(struct libusb_device *dev)
|
||||
{
|
||||
struct device_priv *dpriv = usbi_get_device_priv(dev);
|
||||
struct usb_device_cdesc udc;
|
||||
struct usb_device_fdesc udf;
|
||||
void *buf;
|
||||
int fd, len, err;
|
||||
|
||||
if ((fd = _bus_open(dev->bus_number)) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
usbi_dbg(DEVICE_CTX(dev), "fd %d, addr %d", fd, dev->device_address);
|
||||
|
||||
udc.udc_bus = dev->bus_number;
|
||||
udc.udc_addr = dev->device_address;
|
||||
udc.udc_config_index = USB_CURRENT_CONFIG_INDEX;
|
||||
if (ioctl(fd, USB_DEVICE_GET_CDESC, &udc) < 0) {
|
||||
err = errno;
|
||||
close(fd);
|
||||
return _errno_to_libusb(errno);
|
||||
}
|
||||
|
||||
usbi_dbg(DEVICE_CTX(dev), "active bLength %d", udc.udc_desc.bLength);
|
||||
|
||||
len = UGETW(udc.udc_desc.wTotalLength);
|
||||
buf = malloc((size_t)len);
|
||||
if (buf == NULL)
|
||||
return LIBUSB_ERROR_NO_MEM;
|
||||
|
||||
udf.udf_bus = dev->bus_number;
|
||||
udf.udf_addr = dev->device_address;
|
||||
udf.udf_config_index = udc.udc_config_index;
|
||||
udf.udf_size = len;
|
||||
udf.udf_data = buf;
|
||||
|
||||
usbi_dbg(DEVICE_CTX(dev), "index %d, len %d", udf.udf_config_index, len);
|
||||
|
||||
if (ioctl(fd, USB_DEVICE_GET_FDESC, &udf) < 0) {
|
||||
err = errno;
|
||||
close(fd);
|
||||
free(buf);
|
||||
return _errno_to_libusb(err);
|
||||
}
|
||||
close(fd);
|
||||
|
||||
if (dpriv->cdesc)
|
||||
free(dpriv->cdesc);
|
||||
dpriv->cdesc = buf;
|
||||
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
_sync_control_transfer(struct usbi_transfer *itransfer)
|
||||
{
|
||||
struct libusb_transfer *transfer;
|
||||
struct libusb_control_setup *setup;
|
||||
struct device_priv *dpriv;
|
||||
struct usb_ctl_request req;
|
||||
|
||||
transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
||||
dpriv = usbi_get_device_priv(transfer->dev_handle->dev);
|
||||
setup = (struct libusb_control_setup *)transfer->buffer;
|
||||
|
||||
usbi_dbg(ITRANSFER_CTX(itransfer), "type 0x%x request 0x%x value 0x%x index %d length %d timeout %d",
|
||||
setup->bmRequestType, setup->bRequest,
|
||||
libusb_le16_to_cpu(setup->wValue),
|
||||
libusb_le16_to_cpu(setup->wIndex),
|
||||
libusb_le16_to_cpu(setup->wLength), transfer->timeout);
|
||||
|
||||
req.ucr_addr = transfer->dev_handle->dev->device_address;
|
||||
req.ucr_request.bmRequestType = setup->bmRequestType;
|
||||
req.ucr_request.bRequest = setup->bRequest;
|
||||
/* Don't use USETW, libusb already deals with the endianness */
|
||||
(*(uint16_t *)req.ucr_request.wValue) = setup->wValue;
|
||||
(*(uint16_t *)req.ucr_request.wIndex) = setup->wIndex;
|
||||
(*(uint16_t *)req.ucr_request.wLength) = setup->wLength;
|
||||
req.ucr_data = transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
|
||||
|
||||
if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
|
||||
req.ucr_flags = USBD_SHORT_XFER_OK;
|
||||
|
||||
if (dpriv->devname == NULL) {
|
||||
/*
|
||||
* XXX If the device is not attached to ugen(4) it is
|
||||
* XXX still possible to submit a control transfer but
|
||||
* XXX with the default timeout only.
|
||||
*/
|
||||
int fd, err;
|
||||
|
||||
if ((fd = _bus_open(transfer->dev_handle->dev->bus_number)) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
if (ioctl(fd, USB_REQUEST, &req) < 0) {
|
||||
err = errno;
|
||||
close(fd);
|
||||
return _errno_to_libusb(err);
|
||||
}
|
||||
close(fd);
|
||||
} else {
|
||||
if (ioctl(dpriv->fd, USB_SET_TIMEOUT, &transfer->timeout) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
if (ioctl(dpriv->fd, USB_DO_REQUEST, &req) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
}
|
||||
|
||||
itransfer->transferred = req.ucr_actlen;
|
||||
|
||||
usbi_dbg(ITRANSFER_CTX(itransfer), "transferred %d", itransfer->transferred);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_access_endpoint(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct handle_priv *hpriv;
|
||||
struct device_priv *dpriv;
|
||||
char devnode[16];
|
||||
int fd, endpt;
|
||||
mode_t mode;
|
||||
|
||||
hpriv = usbi_get_device_handle_priv(transfer->dev_handle);
|
||||
dpriv = usbi_get_device_priv(transfer->dev_handle->dev);
|
||||
|
||||
endpt = UE_GET_ADDR(transfer->endpoint);
|
||||
mode = IS_XFERIN(transfer) ? O_RDONLY : O_WRONLY;
|
||||
|
||||
usbi_dbg(TRANSFER_CTX(transfer), "endpoint %d mode %d", endpt, mode);
|
||||
|
||||
if (hpriv->endpoints[endpt] < 0) {
|
||||
/* Pick the right endpoint node */
|
||||
snprintf(devnode, sizeof(devnode), DEVPATH "%s.%02d",
|
||||
dpriv->devname, endpt);
|
||||
|
||||
/* We may need to read/write to the same endpoint later. */
|
||||
if (((fd = open(devnode, O_RDWR)) < 0) && (errno == ENXIO))
|
||||
if ((fd = open(devnode, mode)) < 0)
|
||||
return -1;
|
||||
|
||||
hpriv->endpoints[endpt] = fd;
|
||||
}
|
||||
|
||||
return hpriv->endpoints[endpt];
|
||||
}
|
||||
|
||||
int
|
||||
_sync_gen_transfer(struct usbi_transfer *itransfer)
|
||||
{
|
||||
struct libusb_transfer *transfer;
|
||||
struct device_priv *dpriv;
|
||||
int fd, nr = 1;
|
||||
|
||||
transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
||||
dpriv = usbi_get_device_priv(transfer->dev_handle->dev);
|
||||
|
||||
if (dpriv->devname == NULL)
|
||||
return LIBUSB_ERROR_NOT_SUPPORTED;
|
||||
|
||||
/*
|
||||
* Bulk, Interrupt or Isochronous transfer depends on the
|
||||
* endpoint and thus the node to open.
|
||||
*/
|
||||
if ((fd = _access_endpoint(transfer)) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
if (ioctl(fd, USB_SET_TIMEOUT, &transfer->timeout) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
if (IS_XFERIN(transfer)) {
|
||||
if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
|
||||
if (ioctl(fd, USB_SET_SHORT_XFER, &nr) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
nr = read(fd, transfer->buffer, transfer->length);
|
||||
} else {
|
||||
nr = write(fd, transfer->buffer, transfer->length);
|
||||
}
|
||||
|
||||
if (nr < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
itransfer->transferred = nr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_bus_open(int number)
|
||||
{
|
||||
char busnode[16];
|
||||
|
||||
snprintf(busnode, sizeof(busnode), USBDEV "%d", number);
|
||||
|
||||
return open(busnode, O_RDWR);
|
||||
}
|
||||
1619
lib/libusb/libusb/os/sunos_usb.c
Normal file
1619
lib/libusb/libusb/os/sunos_usb.c
Normal file
File diff suppressed because it is too large
Load Diff
79
lib/libusb/libusb/os/sunos_usb.h
Normal file
79
lib/libusb/libusb/os/sunos_usb.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef LIBUSB_SUNOS_H
|
||||
#define LIBUSB_SUNOS_H
|
||||
|
||||
#include <libdevinfo.h>
|
||||
#include <pthread.h>
|
||||
#include "libusbi.h"
|
||||
|
||||
#define READ 0
|
||||
#define WRITE 1
|
||||
|
||||
typedef struct sunos_device_priv {
|
||||
uint8_t cfgvalue; /* active config value */
|
||||
uint8_t *raw_cfgdescr; /* active config descriptor */
|
||||
char *ugenpath; /* name of the ugen(4) node */
|
||||
char *phypath; /* physical path */
|
||||
} sunos_dev_priv_t;
|
||||
|
||||
typedef struct endpoint {
|
||||
int datafd; /* data file */
|
||||
int statfd; /* state file */
|
||||
} sunos_ep_priv_t;
|
||||
|
||||
typedef struct sunos_device_handle_priv {
|
||||
uint8_t altsetting[USB_MAXINTERFACES]; /* a interface's alt */
|
||||
uint8_t config_index;
|
||||
sunos_ep_priv_t eps[USB_MAXENDPOINTS];
|
||||
sunos_dev_priv_t *dpriv; /* device private */
|
||||
} sunos_dev_handle_priv_t;
|
||||
|
||||
typedef struct sunos_transfer_priv {
|
||||
struct aiocb aiocb;
|
||||
struct libusb_transfer *transfer;
|
||||
} sunos_xfer_priv_t;
|
||||
|
||||
struct node_args {
|
||||
struct libusb_context *ctx;
|
||||
struct discovered_devs **discdevs;
|
||||
const char *last_ugenpath;
|
||||
di_devlink_handle_t dlink_hdl;
|
||||
};
|
||||
|
||||
struct devlink_cbarg {
|
||||
struct node_args *nargs; /* di node walk arguments */
|
||||
di_node_t myself; /* the di node */
|
||||
di_minor_t minor;
|
||||
};
|
||||
|
||||
typedef struct walk_link {
|
||||
char *path;
|
||||
int len;
|
||||
char **linkpp;
|
||||
} walk_link_t;
|
||||
|
||||
/* AIO callback args */
|
||||
struct aio_callback_args{
|
||||
struct libusb_transfer *transfer;
|
||||
struct aiocb aiocb;
|
||||
};
|
||||
|
||||
#endif /* LIBUSB_SUNOS_H */
|
||||
126
lib/libusb/libusb/os/threads_posix.c
Normal file
126
lib/libusb/libusb/os/threads_posix.c
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* libusb synchronization using POSIX Threads
|
||||
*
|
||||
* Copyright © 2011 Vitali Lovich <vlovich@aliph.com>
|
||||
* Copyright © 2011 Peter Stuge <peter@stuge.se>
|
||||
*
|
||||
* 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 <limits.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__)
|
||||
# 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,
|
||||
pthread_mutex_t *mutex, const struct timeval *tv)
|
||||
{
|
||||
struct timespec timeout;
|
||||
int r;
|
||||
|
||||
#ifdef HAVE_PTHREAD_CONDATTR_SETCLOCK
|
||||
usbi_get_monotonic_time(&timeout);
|
||||
#else
|
||||
usbi_get_real_time(&timeout);
|
||||
#endif
|
||||
|
||||
timeout.tv_sec += tv->tv_sec;
|
||||
timeout.tv_nsec += tv->tv_usec * 1000L;
|
||||
if (timeout.tv_nsec >= NSEC_PER_SEC) {
|
||||
timeout.tv_nsec -= NSEC_PER_SEC;
|
||||
timeout.tv_sec++;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
unsigned long usbi_get_tid(void)
|
||||
{
|
||||
static _Thread_local unsigned long tl_tid;
|
||||
unsigned long tid;
|
||||
|
||||
if (tl_tid)
|
||||
return tl_tid;
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
tid = (unsigned long)gettid();
|
||||
#elif defined(__APPLE__)
|
||||
#ifdef HAVE_PTHREAD_THREADID_NP
|
||||
uint64_t thread_id;
|
||||
|
||||
if (pthread_threadid_np(NULL, &thread_id) == 0)
|
||||
tid = (unsigned long)thread_id;
|
||||
else
|
||||
tid = ULONG_MAX;
|
||||
#else
|
||||
tid = (unsigned long)pthread_mach_thread_np(pthread_self());
|
||||
#endif
|
||||
#elif defined(__HAIKU__)
|
||||
tid = (unsigned long)get_pthread_thread_id(pthread_self());
|
||||
#elif defined(__linux__)
|
||||
tid = (unsigned long)syscall(SYS_gettid);
|
||||
#elif defined(__NetBSD__)
|
||||
tid = (unsigned long)_lwp_self();
|
||||
#elif defined(__OpenBSD__)
|
||||
tid = (unsigned long)getthrid();
|
||||
#elif defined(__sun__)
|
||||
tid = (unsigned long)_lwp_self();
|
||||
#else
|
||||
tid = ULONG_MAX;
|
||||
#endif
|
||||
|
||||
if (tid == ULONG_MAX) {
|
||||
/* If we don't have a thread ID, at least return a unique
|
||||
* value that can be used to distinguish individual
|
||||
* threads. */
|
||||
tid = (unsigned long)(uintptr_t)pthread_self();
|
||||
}
|
||||
|
||||
return tl_tid = tid;
|
||||
}
|
||||
98
lib/libusb/libusb/os/threads_posix.h
Normal file
98
lib/libusb/libusb/os/threads_posix.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* libusb synchronization using POSIX Threads
|
||||
*
|
||||
* Copyright © 2010 Peter Stuge <peter@stuge.se>
|
||||
*
|
||||
* 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_THREADS_POSIX_H
|
||||
#define LIBUSB_THREADS_POSIX_H
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#define PTHREAD_CHECK(expression) ASSERT_EQ(expression, 0)
|
||||
|
||||
#define USBI_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
|
||||
typedef pthread_mutex_t usbi_mutex_static_t;
|
||||
static inline void usbi_mutex_static_lock(usbi_mutex_static_t *mutex)
|
||||
{
|
||||
PTHREAD_CHECK(pthread_mutex_lock(mutex));
|
||||
}
|
||||
static inline void usbi_mutex_static_unlock(usbi_mutex_static_t *mutex)
|
||||
{
|
||||
PTHREAD_CHECK(pthread_mutex_unlock(mutex));
|
||||
}
|
||||
|
||||
typedef pthread_mutex_t usbi_mutex_t;
|
||||
static inline void usbi_mutex_init(usbi_mutex_t *mutex)
|
||||
{
|
||||
PTHREAD_CHECK(pthread_mutex_init(mutex, NULL));
|
||||
}
|
||||
static inline void usbi_mutex_lock(usbi_mutex_t *mutex)
|
||||
{
|
||||
PTHREAD_CHECK(pthread_mutex_lock(mutex));
|
||||
}
|
||||
static inline void usbi_mutex_unlock(usbi_mutex_t *mutex)
|
||||
{
|
||||
PTHREAD_CHECK(pthread_mutex_unlock(mutex));
|
||||
}
|
||||
static inline int usbi_mutex_trylock(usbi_mutex_t *mutex)
|
||||
{
|
||||
return pthread_mutex_trylock(mutex) == 0;
|
||||
}
|
||||
static inline void usbi_mutex_destroy(usbi_mutex_t *mutex)
|
||||
{
|
||||
PTHREAD_CHECK(pthread_mutex_destroy(mutex));
|
||||
}
|
||||
|
||||
typedef pthread_cond_t usbi_cond_t;
|
||||
void usbi_cond_init(pthread_cond_t *cond);
|
||||
static inline void usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex)
|
||||
{
|
||||
PTHREAD_CHECK(pthread_cond_wait(cond, mutex));
|
||||
}
|
||||
int usbi_cond_timedwait(usbi_cond_t *cond,
|
||||
usbi_mutex_t *mutex, const struct timeval *tv);
|
||||
static inline void usbi_cond_broadcast(usbi_cond_t *cond)
|
||||
{
|
||||
PTHREAD_CHECK(pthread_cond_broadcast(cond));
|
||||
}
|
||||
static inline void usbi_cond_destroy(usbi_cond_t *cond)
|
||||
{
|
||||
PTHREAD_CHECK(pthread_cond_destroy(cond));
|
||||
}
|
||||
|
||||
typedef pthread_key_t usbi_tls_key_t;
|
||||
static inline void usbi_tls_key_create(usbi_tls_key_t *key)
|
||||
{
|
||||
PTHREAD_CHECK(pthread_key_create(key, NULL));
|
||||
}
|
||||
static inline void *usbi_tls_key_get(usbi_tls_key_t key)
|
||||
{
|
||||
return pthread_getspecific(key);
|
||||
}
|
||||
static inline void usbi_tls_key_set(usbi_tls_key_t key, void *ptr)
|
||||
{
|
||||
PTHREAD_CHECK(pthread_setspecific(key, ptr));
|
||||
}
|
||||
static inline void usbi_tls_key_delete(usbi_tls_key_t key)
|
||||
{
|
||||
PTHREAD_CHECK(pthread_key_delete(key));
|
||||
}
|
||||
|
||||
unsigned long usbi_get_tid(void);
|
||||
|
||||
#endif /* LIBUSB_THREADS_POSIX_H */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user