chore(rust): update toolchain and dependencies with preserved vendor sources

This commit is contained in:
zarzet committed 2026-10-11 14:33:45 +07:00
1 parent 5caa2ed588
commit 08032f1877
441 files changed
+43030 -520

No files matched your search

+5 -3
View File
@@ -13,7 +13,7 @@ gradlew text eol=lf
android/app/src/test/resources/lyrics_usability_cases.tsv whitespace=-blank-at-eol
# Retain upstream dependency sources for the Android compatibility patch.
rust_backend/vendor/** linguist-vendored
rust_backend/vendor/** linguist-vendored -text
third_party/audio_service/** linguist-vendored
# Keep the pinned package byte-for-byte outside the documented native patch.
third_party/audio_service/CHANGELOG.md whitespace=-blank-at-eol
@@ -22,8 +22,10 @@ third_party/audio_service/android/src/main/java/com/ryanheise/audioservice/Audio
third_party/audio_service/darwin/audio_service/Sources/audio_service/AudioServicePlugin.m whitespace=-blank-at-eol
third_party/audio_service/darwin/audio_service.podspec whitespace=-blank-at-eof
# Preserve the original whitespace in upstream license and policy documents.
rust_backend/vendor/rustix-1.1.4/LICENSE-Apache-2.0_WITH_LLVM-exception whitespace=-blank-at-eof
rust_backend/vendor/rustix-1.1.4/ORG_CODE_OF_CONDUCT.md whitespace=-blank-at-eol
rust_backend/vendor/rustix-1.1.5/LICENSE-Apache-2.0_WITH_LLVM-exception whitespace=-blank-at-eof
rust_backend/vendor/rustix-1.1.5/ORG_CODE_OF_CONDUCT.md whitespace=-blank-at-eol
# Preserve libusb's upstream sources, license whitespace, and source hashes.
rust_backend/vendor/libusb1-sys-0.7.0/** -whitespace
# Binary files
*.png binary
+3 -2
View File
@@ -1,8 +1,9 @@
USB direct audio dependencies
libusb1-sys 0.7.0 (MIT) and its bundled libusb (LGPL-2.1-or-later).
libusb1-sys 0.7.0 (MIT), bundled with libusb 1.0.30 (LGPL-2.1-or-later).
Source: https://crates.io/crates/libusb1-sys/0.7.0
The unmodified dependency is pinned in rust_backend/Cargo.lock. Source for
libusb source: https://github.com/libusb/libusb/releases/tag/v1.0.30
The dependency and updated C sources are pinned in rust_backend/vendor. Source for
SpotiFLAC and scripts/build_rust_backend.sh is available at
https://github.com/spotiflacapp/SpotiFLAC-Mobile for rebuilding/relinking the
Android native library with a modified libusb. This component's LGPL rights,
+92 -75
View File
@@ -114,7 +114,7 @@ dependencies = [
"rustc-hash",
"serde",
"serde_derive",
"syn 3.0.6",
"syn 3.0.7",
]
[[package]]
@@ -180,9 +180,9 @@ dependencies = [
[[package]]
name = "async-compression"
version = "0.4.48"
version = "0.4.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb61aea1a7def73ee7c350a184f0e70b32c182344e2e75bf70c9b621b83417fd"
checksum = "ee19bd99b43e3691acbad4e840420a4881cea6c0b66a208125a824f8fd53f5a1"
dependencies = [
"compression-codecs",
"compression-core",
@@ -367,9 +367,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.5.1"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f360145194ee8e21db5ee7f3fcd4fe52210864c75c985dae33218202c8bbe040"
checksum = "50a649af8a827553c29fb0cb4bd4a6f1a0dd695bd3232b9bc98bd9c8a3ffbb8b"
dependencies = [
"find-msvc-tools",
"shlex 2.0.1",
@@ -390,6 +390,12 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
[[package]]
name = "cfg_aliases"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527"
[[package]]
name = "chacha20"
version = "0.10.2"
@@ -465,7 +471,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 3.0.6",
"syn 3.0.7",
]
[[package]]
@@ -504,9 +510,9 @@ dependencies = [
[[package]]
name = "compression-codecs"
version = "0.4.43"
version = "0.4.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef16c47ba2797aa6a909cc37d39911f3a6743811fe7408ac0b0cc0276b656e9"
checksum = "98fc98460ba0ad5317075d3632b8dfc45d0be8c4a49347c2a38272019717614a"
dependencies = [
"compression-core",
"flate2",
@@ -621,7 +627,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d045de693cb712d0b22c6a64be5b953f67b3ce00ab5ad3dd5d8b441886ab8e1a"
dependencies = [
"quote",
"syn 3.0.6",
"syn 3.0.7",
]
[[package]]
@@ -635,9 +641,9 @@ dependencies = [
[[package]]
name = "ctutils"
version = "0.4.2"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e"
checksum = "03bb0e1cc970d482d121d9a1744999169b69a07470b3d644a7894e53fcaf4574"
dependencies = [
"cmov",
]
@@ -709,7 +715,7 @@ checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8"
dependencies = [
"proc-macro2",
"quote",
"syn 3.0.6",
"syn 3.0.7",
]
[[package]]
@@ -735,9 +741,9 @@ checksum = "b04dc5a38e4f151a79d9f2451ae6037fb6eaf5cba34771f44781f80e508498e3"
[[package]]
name = "either"
version = "1.18.0"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34"
checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be"
[[package]]
name = "equivalent"
@@ -822,9 +828,9 @@ dependencies = [
[[package]]
name = "fs-err"
version = "3.3.1"
version = "3.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b91aa448ca50d7e79433bdf3ee8d99215430d2ec02ade5aefab2a073a1822e8a"
checksum = "b5c95b673b8f6f7235229ae11c5642d81b04c2e64c1e2fb417bc0cf73ca45f29"
dependencies = [
"autocfg",
]
@@ -863,7 +869,7 @@ checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44"
dependencies = [
"proc-macro2",
"quote",
"syn 3.0.6",
"syn 3.0.7",
]
[[package]]
@@ -952,9 +958,9 @@ dependencies = [
[[package]]
name = "h2"
version = "0.4.19"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef8e5e5a340588f4452631496976cf8636d4a7ecf600239fdc27615d2530bc16"
checksum = "7d29020232d6aa3fb1daca64c1127cf662cf97f254ae16c18c05b8ab635fc118"
dependencies = [
"atomic-waker",
"bytes",
@@ -1099,9 +1105,9 @@ dependencies = [
[[package]]
name = "hyper"
version = "1.11.1"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27b501faa50e7a26c3d3560ca625132f4078a17771f4810baf70475ae48cbe43"
checksum = "2c3e324da4c95177d6291d4c8730197c0d1822f8a9766814a4a44fa5ab797c9c"
dependencies = [
"atomic-waker",
"bytes",
@@ -1436,15 +1442,15 @@ dependencies = [
[[package]]
name = "lazy_static"
version = "1.5.0"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
checksum = "20870f649af7073d53e38067b2a84312175d56ea15217e1b15bc83506ec50afb"
[[package]]
name = "libc"
version = "0.2.189"
version = "0.2.190"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78"
[[package]]
name = "libloading"
@@ -1470,8 +1476,6 @@ dependencies = [
[[package]]
name = "libusb1-sys"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da050ade7ac4ff1ba5379af847a10a10a8e284181e060105bf8d86960ce9ce0f"
dependencies = [
"cc",
"libc",
@@ -1567,9 +1571,9 @@ dependencies = [
[[package]]
name = "mio"
version = "1.2.3"
version = "1.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b18443e9c262bfe8fa82f51666e2642c53393f7e5c27b3e1aeab922cff5b9d8"
checksum = "1788edb87fdc09c7e26304471e2f5be8cdefb1b6930d6e3985fc02ff53bf86ee"
dependencies = [
"libc",
"wasi",
@@ -1592,6 +1596,18 @@ version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
[[package]]
name = "nix"
version = "0.31.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d"
dependencies = [
"bitflags",
"cfg-if",
"cfg_aliases",
"libc",
]
[[package]]
name = "nom"
version = "7.1.3"
@@ -1812,9 +1828,9 @@ dependencies = [
[[package]]
name = "powerfmt"
version = "0.2.0"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
checksum = "4a6394b9e965e73d0a289ee54f589087e2c676aedf60885baf52c76b771e4958"
[[package]]
name = "precomputed-hash"
@@ -1948,9 +1964,9 @@ checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
[[package]]
name = "relative-path"
version = "2.0.1"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bca40a312222d8ba74837cb474edef44b37f561da5f773981007a10bbaa992b0"
checksum = "f2a073568cd8b9c4825429d3e9fc5f52851b4f97cc1348800689408921e6b8f8"
dependencies = [
"serde",
]
@@ -2011,7 +2027,7 @@ dependencies = [
"proc-macro2",
"quote",
"rquickjs-core",
"syn 3.0.6",
"syn 3.0.7",
]
[[package]]
@@ -2075,7 +2091,7 @@ dependencies = [
[[package]]
name = "rustix"
version = "1.1.4"
version = "1.1.5"
dependencies = [
"bitflags",
"errno",
@@ -2319,14 +2335,14 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
dependencies = [
"proc-macro2",
"quote",
"syn 3.0.6",
"syn 3.0.7",
]
[[package]]
name = "serde_json"
version = "1.0.151"
version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
checksum = "1741ab7a6cc54a03a89b5d563ed60075c277d9e3cfa73ad0c1f23f23974703c6"
dependencies = [
"itoa",
"memchr",
@@ -2337,9 +2353,9 @@ dependencies = [
[[package]]
name = "serde_spanned"
version = "1.1.1"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26"
checksum = "4e7523beb55eece201a2356bee0bbca0d1ab466c14c07703b2e0ee6d42cb0c2c"
dependencies = [
"serde_core",
]
@@ -2423,9 +2439,9 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
[[package]]
name = "smallvec"
version = "1.16.2"
version = "1.16.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9395f0f0eee849a9b707b2f06bb92a6a422090e2123bb2ef8e87a0e61892a8e"
checksum = "5b3dc8af474f516a851ff4bd12db780f948b9250ad37211e4eec0bccea54e01b"
[[package]]
name = "smawk"
@@ -2648,9 +2664,9 @@ dependencies = [
[[package]]
name = "syn"
version = "3.0.6"
version = "3.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee"
checksum = "d62a2e0561533f2ca2561d0cf27fd9fedb640a1bf2616ff5d5c80d99017faadc"
dependencies = [
"proc-macro2",
"quote",
@@ -2676,7 +2692,7 @@ checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02"
dependencies = [
"proc-macro2",
"quote",
"syn 3.0.6",
"syn 3.0.7",
]
[[package]]
@@ -2728,7 +2744,7 @@ checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524"
dependencies = [
"proc-macro2",
"quote",
"syn 3.0.6",
"syn 3.0.7",
]
[[package]]
@@ -2779,9 +2795,9 @@ checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee"
[[package]]
name = "tokio"
version = "1.53.1"
version = "1.53.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed"
checksum = "e95f91fcc7a621e8b030f6aa23c71fe9838ae2fb4d8118b75602a328f5144044"
dependencies = [
"bytes",
"libc",
@@ -2800,14 +2816,14 @@ checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e"
dependencies = [
"proc-macro2",
"quote",
"syn 3.0.6",
"syn 3.0.7",
]
[[package]]
name = "tokio-rustls"
version = "0.26.5"
version = "0.26.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0c85f2c3ef0b1cd58b36682f4b17aaa995f0e5db534d85692b4903abce21f67"
checksum = "c9cc2678c2cdd569ef8215e2afd7954ada2ae20b4fdd2c5fe6139a3b02d105db"
dependencies = [
"rustls",
"tokio",
@@ -2815,9 +2831,9 @@ dependencies = [
[[package]]
name = "tokio-util"
version = "0.7.19"
version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52"
checksum = "e464cf451ba96ebfc6f9b6542f17ee8b8956e33f1e40d9690624e59d7a7f8a4b"
dependencies = [
"bytes",
"futures-core",
@@ -2829,9 +2845,9 @@ dependencies = [
[[package]]
name = "toml"
version = "1.1.6+spec-1.1.0"
version = "1.1.8+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "920602543f0911ab71da12c50d59701da54c196d1a2bf5cb4b75667f137a406a"
checksum = "20489e00e4d8741d6be680764cc12e270655e375a20d1011e844a9c3379e678d"
dependencies = [
"indexmap",
"serde_core",
@@ -2844,18 +2860,18 @@ dependencies = [
[[package]]
name = "toml_datetime"
version = "1.1.1+spec-1.1.0"
version = "1.1.2+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7"
checksum = "2b86d767906c6c42421dcba507eb9d203e779497710a47782a224bb871653053"
dependencies = [
"serde_core",
]
[[package]]
name = "toml_edit"
version = "0.25.15+spec-1.1.0"
version = "0.25.17+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1340ea94a5856333492c9064b02c778b191dd2c853778d9609debdcdfea3a614"
checksum = "e3641d5bbb5349a79e1020a242d251efbc546ad8048d133958323ce9c40a9c9c"
dependencies = [
"indexmap",
"toml_datetime",
@@ -2865,18 +2881,18 @@ dependencies = [
[[package]]
name = "toml_parser"
version = "1.1.3+spec-1.1.0"
version = "1.1.5+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56"
checksum = "baa693a8032d7e1cada7d0041e96126df243179ff061456783ac7f12bda4744c"
dependencies = [
"winnow",
]
[[package]]
name = "toml_writer"
version = "1.1.2+spec-1.1.0"
version = "1.1.3+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2"
checksum = "06bdbd8cfc056b8d2e2e85f29b56a3bdbecb527cef81eb39e3e7b98af4652770"
[[package]]
name = "tower-service"
@@ -3139,9 +3155,9 @@ dependencies = [
[[package]]
name = "want"
version = "0.3.1"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
checksum = "ec4cdd0dd910afe868b7ef477227d8d538b46b3075031afee8a9f2acb0a2ed0b"
dependencies = [
"try-lock",
]
@@ -3184,7 +3200,7 @@ dependencies = [
"bumpalo",
"proc-macro2",
"quote",
"syn 3.0.6",
"syn 3.0.7",
"wasm-bindgen-shared",
]
@@ -3532,13 +3548,13 @@ dependencies = [
[[package]]
name = "yoke-derive"
version = "0.8.3"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33811428bee40dbceb6d545e95754741d17a6aef9a4849f0fd62e2ba4f412a78"
checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71"
dependencies = [
"proc-macro2",
"quote",
"syn 3.0.6",
"syn 3.0.7",
"synstructure 0.14.0",
]
@@ -3559,15 +3575,15 @@ checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a"
dependencies = [
"proc-macro2",
"quote",
"syn 3.0.6",
"syn 3.0.7",
"synstructure 0.14.0",
]
[[package]]
name = "zeroize"
version = "1.9.0"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e"
checksum = "e13084392c5e4bc371903e2935a5eaeed24905a7511356b883835e18a78f6879"
[[package]]
name = "zerotrie"
@@ -3599,19 +3615,20 @@ checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da"
dependencies = [
"proc-macro2",
"quote",
"syn 3.0.6",
"syn 3.0.7",
]
[[package]]
name = "zip"
version = "8.6.0"
version = "9.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d04a6b5381502aa6087c94c669499eb1602eb9c5e8198e534de571f7154809b"
checksum = "e49ade69c4434c55dd651d36fe05f38e0578db948b773cbc01c48c4b5e560692"
dependencies = [
"crc32fast",
"flate2",
"indexmap",
"memchr",
"nix",
"typed-path",
]
+8 -7
View File
@@ -1,17 +1,18 @@
[workspace]
members = ["crates/core", "crates/network", "crates/providers", "crates/extensions", "crates/mobile", "crates/bindgen"]
exclude = ["vendor/rustix-1.1.4"]
exclude = ["vendor/rustix-1.1.5", "vendor/libusb1-sys-0.7.0"]
resolver = "3"
[patch.crates-io]
# Android < 30 may kill processes that probe statx directly (SIGSYS).
# Keep all direct and transitive users on the same compatibility fix.
rustix = { path = "vendor/rustix-1.1.4" }
rustix = { path = "vendor/rustix-1.1.5" }
libusb1-sys = { path = "vendor/libusb1-sys-0.7.0" }
[workspace.package]
version = "0.1.0"
edition = "2024"
rust-version = "1.98.1"
rust-version = "1.99.0"
license = "MIT"
publish = false
@@ -33,13 +34,13 @@ blowfish = { version = "=0.10.0", features = ["zeroize"] }
zeroize = "1.8"
getrandom = "0.4"
tempfile = "3.27"
zip = { version = "=8.6.0", default-features = false, features = ["deflate-flate2-zlib-rs"] }
zip = { version = "=9.0.1", default-features = false, features = ["deflate-flate2-zlib-rs"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0", features = ["float_roundtrip", "raw_value"] }
thiserror = "2.0"
uniffi = { version = "=0.32.2", default-features = false }
tokio = { version = "=1.53.1", features = ["rt-multi-thread", "net", "time", "sync", "io-util", "macros"] }
hyper = { version = "=1.11.1", features = ["client", "http1", "http2"] }
tokio = { version = "=1.53.2", features = ["rt-multi-thread", "net", "time", "sync", "io-util", "macros"] }
hyper = { version = "=1.12.0", features = ["client", "http1", "http2"] }
hyper-util = { version = "=0.1.21", features = ["client-legacy", "http1", "http2", "tokio"] }
hyper-rustls = { version = "=0.27.10", default-features = false, features = ["http1", "http2", "ring", "tls12"] }
rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12"] }
@@ -70,7 +71,7 @@ chrono = { version = "=0.4.45", default-features = false, features = ["clock"] }
tz-rs = "=0.7.3"
httpdate = "=1.0.3"
cap-std = "=4.0.3"
rustix = { version = "=1.1.4", features = ["fs"] }
rustix = { version = "=1.1.5", features = ["fs"] }
[workspace.lints.rust]
unsafe_code = "deny"
+1 -1
View File
@@ -35,7 +35,7 @@ cap-std.workspace = true
rustix.workspace = true
[dev-dependencies]
libc = "=0.2.189"
libc = "=0.2.190"
rustls.workspace = true
rcgen = { version = "=0.14.10", default-features = false, features = ["crypto", "ring", "pem"] }
@@ -198,7 +198,7 @@ impl MusicBrainzClient {
.filter(|flight| {
flight
.waiters
.fetch_update(Ordering::AcqRel, Ordering::Acquire, |count| {
.try_update(Ordering::AcqRel, Ordering::Acquire, |count| {
(count > 0).then_some(count + 1)
})
.is_ok()
@@ -132,7 +132,7 @@ impl ResolverHttp {
self.timeout,
check,
)
.map_err(&failure)?;
.map_err(failure)?;
let status = stream.response.status;
if language.is_none() && status != 200 && !(post && status == 201) {
return Err(ResolverError::Failed(format!("HTTP {status}")));
@@ -172,7 +172,7 @@ impl ResolverHttp {
let capacity = buffer.len().min(limit + 1 - body.len());
let read = stream
.read(&mut buffer[..capacity], check)
.map_err(&failure)?;
.map_err(failure)?;
if read == 0 {
break;
}
+1 -1
View File
@@ -1,4 +1,4 @@
[toolchain]
channel = "1.98.1"
channel = "1.99.0"
profile = "minimal"
components = ["rustfmt", "clippy"]
+18 -2
View File
@@ -1,10 +1,10 @@
# Rustix Android compatibility patch
`rustix-1.1.4` is vendored from the pinned crates.io package using `cargo vendor`.
`rustix-1.1.5` is vendored from the pinned crates.io package using `cargo vendor`.
Its upstream license files are retained. Cargo's workspace patch applies to both
direct users and transitive dependencies such as `cap-std`.
The original package checksum is
`b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190`.
`891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d`.
The sole upstream source change is in `src/backend/libc/fs/syscalls.rs`: Android
uses `weakcall!` for `statx`, rather than `weak_or_syscall!`. Bionic exports this
@@ -28,3 +28,19 @@ symbol and blocks the raw syscall to exercise the legacy fallback. A final probe
deliberately exits with `SIGSYS` to verify that the filter is active. Neither the
symbol wrapper nor the filter is included in the application. This simulated
sandbox check complements testing the APK on an actual older ARM32 device.
# libusb native source update
`libusb1-sys-0.7.0` is the latest stable Rust binding. Its upstream bundle is
libusb 1.0.27, so the workspace patch replaces the C source directory and MSVC
configuration with the official libusb 1.0.30 release. The Rust API and bindings
are unchanged; `build.rs` reports 1.0.30 when compiling the vendored C library.
The Android dependency keeps its `vendored` feature, so both APK ABIs use these
sources instead of an arbitrary host installation. Upstream licenses are retained.
Source: https://github.com/libusb/libusb/releases/download/v1.0.30/libusb-1.0.30.tar.bz2
SHA-256: `fea36f34f9156400209595e300840767ab1a385ede1dc7ee893015aea9c6dbaf`
The `.cargo-checksum.json` file lists the updated local source hashes while
retaining the original registry package checksum as provenance. The same applies
to the Rustix compatibility patch above.
@@ -0,0 +1 @@
{"$comment":"This file only protects against accidental modifications. It is not a security mechanism and does not protect against malicious changes.","files":{".cargo_vcs_info.json":"6b8d40d082d2128d22ecdb48aaf2a0df27bc65b2711f45d970da950b245aa8cd","CHANGELOG.md":"214a0fe6a85bc7e3d50c06aa0aa0ded81fbd9135f2b20e36e922725b088603a9","Cargo.lock":"a3be52c6f430b6b3b6b7b98e6d217c9ff811be7bfe73c99acf8d896473cce222","Cargo.toml":"ccd78a0b446d7157c26d42f8c15b750826ce75c2226ccfb8397e672a4cf6fe0e","Cargo.toml.orig":"b65c0545773db1b9f3c2bf9cca86665be12bdb2954cbbdc46ce4f09aa0257731","LICENSE":"d6b63b280f7998e4a5e9e21c7b0d2dbe79426e1b28a75e39e41bb8feae0f8b03","README.md":"d30d9e32743be8ed4a70403f574f12760d361d888e413729cc7c3bd050e04fd1","build.rs":"8bc9e8254d4a3865aa09f0774b65e5a48da8a7eff125c56136a701e758ceb5ef","libusb/AUTHORS":"27fd82b016838197d5276ba98d2187ed5a1ad0e171767322f356f0a9f6395941","libusb/COPYING":"5df07007198989c622f5d41de8d703e7bef3d0e79d62e24332ee739a452af62a","libusb/README":"ba152b9ae04b7cdf3cf09e8c91f60971b0c8f6106562e7cd31a2f2bf97f690db","libusb/README.md":"a6ef009aeac750d2bdd413c12fd3a596ecff40e1898d43b05ead0e5657d8d7ad","libusb/libusb/Makefile.am":"9fd9d63c9ecc678f3c4de2b40365ed5b79cce790184658c678335826466dad3d","libusb/libusb/Makefile.am.extra":"ce1da989a10a415739061fd4b9eaa3ff98f82cca59c27200800d9029ff697f34","libusb/libusb/Makefile.in":"cb56dd89300752b4c242925c6744fa663b04f3501bbc76a2d1e99e15cbb1749b","libusb/libusb/core.c":"33db091fdf75b690f9c5daf65ca8e3124978e897c2824d97fbc97567afea1d7b","libusb/libusb/descriptor.c":"4e80077f28a033ba07befceac0347a64ea0e23c34c93b96cfaf8b188d69e401d","libusb/libusb/hotplug.c":"7cf1e723dbae5427dd93fe8419d8efa3f3502d6def30a763b8c210e9780529fb","libusb/libusb/io.c":"c83a9e14b9ff8b9566e42d23d1e90c919e223fd1e04721c5ca1a3aff13239a3d","libusb/libusb/libusb-1.0.def":"4a07f2ea772f7f8bb3e117aa2c2141a79f1021afb4039be7588c1551fe9af66e","libusb/libusb/libusb-1.0.rc":"ca4851b3ca88161d9576bb2685588239cdaa4ba694013d50da6b8f5a602a18ab","libusb/libusb/libusb.h":"a61260ab145b051b86df2b0575956f01810190abe2c7df6aca831c33bdc8082c","libusb/libusb/libusbi.h":"cc234f9532988e492459b877cfd2e5e90704555a2a0a5310ee4add39627c7ed9","libusb/libusb/os/darwin_usb.c":"290b9913eba18e0f9f9fa0de75c59bec0daa4ccd02740a96fd8479d20da06557","libusb/libusb/os/darwin_usb.h":"fd26ccfdbf5fe02dc6f977e07e57a7cb3897bf9c88d19e60cc06f2b1fb12fcc1","libusb/libusb/os/emscripten_webusb.cpp":"dd8f91bbc3e1c75974c27a27fa2c162c285e3e3f5ef1a3c64018564656e758dd","libusb/libusb/os/events_posix.c":"aabddcc6ca86faba726ca87862eef9fc5d3b3168faef99c5be22827ac5b66ec0","libusb/libusb/os/events_posix.h":"f93e407eddc235375aace26fd17065e297cd963e60602002a6c100214a300b1b","libusb/libusb/os/events_windows.c":"726bdaeabb280c83681b88848d9a1526f73d3cd5f30b1aaf43dbd303e865148a","libusb/libusb/os/events_windows.h":"0690b9e46d32c02a9da65669128cabfa67f61dc6c234331c527a8eda4c98a1ea","libusb/libusb/os/haiku_pollfs.cpp":"4a9c603e1c44a00b6887720d88e5d71b08cc133954cef867243188829f7971cd","libusb/libusb/os/haiku_usb.h":"7b843867f3c5666a999326ca417b4ad2207114fcc593fc988d7706691aea8fb9","libusb/libusb/os/haiku_usb_backend.cpp":"fd10f1989f53002423fbab8041c6a20c5942f268f26ea80933a21a3d020f473d","libusb/libusb/os/haiku_usb_raw.cpp":"ebaee896cc0d2f0e196186811a6e42c27f8938b1fe4541a6acba40c715d0d537","libusb/libusb/os/haiku_usb_raw.h":"32c14b81a85481a983c6954e7d7fdd2ac0a4c67a4af23400b7af16afc5975aa3","libusb/libusb/os/linux_netlink.c":"6ad9b928501ad36dd9fffdbe713a9cdd9d4533b8324190bd060001528d8374f0","libusb/libusb/os/linux_udev.c":"0ca06ccb2341f008d09465b4142154a93240abd946d3298b4ced6c2ea9248115","libusb/libusb/os/linux_usbfs.c":"ac4401cec575cc2f12b71377cced5e5943e72366eedeffbe42e951134b26bd54","libusb/libusb/os/linux_usbfs.h":"a5deb9f3d62c1ec8fdeb9fa95717cb9d0717fdf1758aa2dad629e82906a3738e","libusb/libusb/os/netbsd_usb.c":"08ccca22489f1e102faca1ac934f23c347fba92a6b743796893950697f01115d","libusb/libusb/os/null_usb.c":"b41e75a6948803c3914e2b2012771ce75f2ae3aefe098a3c7c58c0c5e5a2c461","libusb/libusb/os/openbsd_usb.c":"1f084b5e83005a2c6942ae6ec6ab78cccd3a4eb5a63c778ff8adc5a155bf4b93","libusb/libusb/os/sunos_usb.c":"5a00462399b83501ba167dc49da622e903df28815fcfe2bd9c0704fe121a18c1","libusb/libusb/os/sunos_usb.h":"f1d312d8ba96af02a9688608b24d4abbdcc7c46f189cc700530179d5d5d68851","libusb/libusb/os/threads_posix.c":"779daa724575cd82c607563c9fe396b53d6f20c6a512444661e29ac30b82210a","libusb/libusb/os/threads_posix.h":"a85fbf402195885a8b0484b881b27ad56e22059655e86cf101d67b40fe1ff261","libusb/libusb/os/threads_windows.c":"33c5124b46509e59393bbc6da0f090325737a9666ae147d0776225c5b29c209b","libusb/libusb/os/threads_windows.h":"6bbf1b429a5abef2705e0c7ecb15daeea5e623f8dcb3312fc06e52a77a5e3a26","libusb/libusb/os/windows_common.c":"b1c26832c25d71bca4a50668f08a3728b26c6e2d398df4d5affb0da063b33e0f","libusb/libusb/os/windows_common.h":"01164ac769e7c90e5bfe0991cf40e0577b80ebd35ed73486994e6f8630fe052b","libusb/libusb/os/windows_hotplug.c":"28a145ee5ec8a08dc50a258efe2cd4701fbLine truncated
@@ -0,0 +1,6 @@
{
"git": {
"sha1": "f4fc94e886d55969ea13c21ab0fc2ab5fa788ffc"
},
"path_in_vcs": "libusb1-sys"
}
+54
View File
@@ -0,0 +1,54 @@
# Changes
## 0.7.0
* fix: Add missing fields to libusb_bos_descriptor and libusb_bos_dev_capability_descriptor [#161]
* Bump libusb to 1.0.27 [#201]
* Remove unneeded mut [#204]
[#161]: https://github.com/a1ien/rusb/pull/161
[#201]: https://github.com/a1ien/rusb/pull/201
[#204]: https://github.com/a1ien/rusb/pull/204
## 0.6.5
* Support pkg_config for MSVC. [#191]
* Fix package detection and build when cross-compiling from MSVC to GNU [#180]
* libusb_set_iso_packet_lengths panics on debug builds in newest nightly (2024-03-27) [#199]
* Added libusb_free_pollfds() in the available FFI methods. [#203]
[#191]: https://github.com/a1ien/rusb/pull/191
[#180]: https://github.com/a1ien/rusb/pull/180
[#199]: https://github.com/a1ien/rusb/pull/199
[#203]: https://github.com/a1ien/rusb/pull/203
## 0.6.3-0.6.4
* Patch for macOS Big Sur and newer allowing to link statically [#133]
* Add libudev include paths as specified by pkg-config [#140]
[#133]: https://github.com/a1ien/rusb/pull/133
[#140]: https://github.com/a1ien/rusb/pull/140
## 0.6.2
* Rename compiled library when vendored libusb is used [#130]
[#130]: https://github.com/a1ien/rusb/pull/130
## 0.6.1
* Add LIBUSB_OPTION_NO_DEVICE_DISCOVERY constant
* Bump vendored libusb version from 1.0.24 to 1.0.25 [#119]
[#119]: https://github.com/a1ien/rusb/pull/119
## 0.6.0
* Allow null function pointers for libusb_set_log_cb() [#74]
* Allow null function pointers for libusb_set_pollfd_notifiers() [#71]
* Fix building of recent libusb on macOS [#108]
* Ignore vendored feature on FreeBSD [#109]
* Update definitions [#112]
[#74]: https://github.com/a1ien/rusb/pull/74
[#71]: https://github.com/a1ien/rusb/pull/71
[#108]: https://github.com/a1ien/rusb/pull/108
[#109]: https://github.com/a1ien/rusb/pull/109
[#112]: https://github.com/a1ien/rusb/pull/112
+37
View File
@@ -0,0 +1,37 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "cc"
version = "1.0.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311"
[[package]]
name = "libc"
version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
[[package]]
name = "libusb1-sys"
version = "0.7.0"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "pkg-config"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
[[package]]
name = "vcpkg"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c"
+64
View File
@@ -0,0 +1,64 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
name = "libusb1-sys"
version = "0.7.0"
authors = [
"David Cuddeback <david.cuddeback@gmail.com>",
"Ilya Averyanov <a1ien.n3t@gmail.com>",
]
build = "build.rs"
links = "usb-1.0"
include = [
"/exaples",
"/libusb/libusb",
"/libusb/msvc",
"/src/*",
"/tests",
"build.rs",
"Cargo.toml",
"LICENSE",
"README.md",
"CHANGELOG.md",
"COPYING",
"AUTHORS",
]
description = "FFI bindings for libusb."
homepage = "https://github.com/a1ien/rusb"
readme = "README.md"
keywords = [
"usb",
"libusb",
"hardware",
"bindings",
]
license = "MIT"
repository = "https://github.com/a1ien/rusb.git"
[dependencies.libc]
version = "0.2"
[build-dependencies.cc]
version = "1.0"
[build-dependencies.pkg-config]
version = "0.3"
[features]
vendored = []
[target."cfg(target_os = \"windows\")".build-dependencies.vcpkg]
version = "0.2"
[badges.travis-ci]
repository = "a1ien/libusb1-sys"
+47
View File
@@ -0,0 +1,47 @@
[package]
name = "libusb1-sys"
version = "0.7.0"
authors = ["David Cuddeback <david.cuddeback@gmail.com>",
"Ilya Averyanov <a1ien.n3t@gmail.com>"]
description = "FFI bindings for libusb."
license = "MIT"
homepage = "https://github.com/a1ien/rusb"
repository = "https://github.com/a1ien/rusb.git"
readme = "README.md"
keywords = ["usb", "libusb", "hardware", "bindings"]
edition = "2018"
links = "usb-1.0" # Required for metadata passing to work
include = [
"/exaples",
"/libusb/libusb",
"/libusb/msvc",
"/src/*",
"/tests",
"build.rs",
"Cargo.toml",
"LICENSE",
"README.md",
"CHANGELOG.md",
"COPYING",
"AUTHORS",
]
build = "build.rs"
[badges]
travis-ci = { repository = "a1ien/libusb1-sys" }
[features]
vendored = []
[dependencies]
libc = "0.2"
[target.'cfg(target_os = "windows")'.build-dependencies]
vcpkg = "0.2"
[build-dependencies]
cc = "1.0"
pkg-config = "0.3"
+21
View File
@@ -0,0 +1,21 @@
Copyright (c) 2015 David Cuddeback
2019 Ilya Averyanov
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+92
View File
@@ -0,0 +1,92 @@
# Libusb Rust Bindings
The `libusb1-sys` crate provides declarations and linkage for the `libusb` C library. Following the
`*-sys` package conventions, the `libusb1-sys` crate does not define higher-level abstractions over
the native `libusb` library functions.
## Dependencies
In order to use the `libusb1-sys` crate, you must have the `libusb` library installed where it can be
found by `pkg-config`.
All systems supported by `libusb` are also supported by the `libusb1-sys` crate. It's been tested on
Linux, OS X, and Windows.
### Cross-Compiling
To link to a cross-compiled version of the native `libusb` library, it's necessary to set several
environment variables to configure `pkg-config` to work with a cross-compiler's sysroot. [Autotools
Mythbuster](https://autotools.io/) has a good explanation of [supporting
cross-compilation](https://autotools.io/pkgconfig/cross-compiling.html) with `pkg-config`.
However, Rust's [`pkg-config` build helper](https://github.com/alexcrichton/pkg-config-rs) doesn't
support calling a `$CHOST`-prefixed `pkg-config`. It will always call `pkg-config` without a prefix.
To cross-compile `libusb1-sys` with the `pkg-config` build helper, one must define the environment
variables `PKG_CONFIG_DIR`, `PKG_CONFIG_LIBDIR`, and `PKG_CONFIG_SYSROOT_DIR` for the *default*
`pkg-config`. It's also necessary to set `PKG_CONFIG_ALLOW_CROSS` to tell Rust's `pkg-config` helper
that it's okay to proceed with a cross-compile.
To adapt the `pkg-config` wrapper in the Autotools Mythbuster guide so that it works with Rust, one
will end up with a script similar to the following:
```sh
#!/bin/sh
SYSROOT=/build/root
export PKG_CONFIG_DIR=
export PKG_CONFIG_LIBDIR=${SYSROOT}/usr/lib/pkgconfig:${SYSROOT}/usr/share/pkgconfig
export PKG_CONFIG_SYSROOT_DIR=${SYSROOT}
export PKG_CONFIG_ALLOW_CROSS=1
cargo build
```
## Usage
Add `libusb1-sys` as a dependency in `Cargo.toml`:
```toml
[dependencies]
libusb1-sys = "0.6"
```
Import the `libusb1_sys` crate and use the functions as they're defined in the native `libusb`
library. See the [`libusb` 1.0 API documention](http://libusb.sourceforge.net/api-1.0/) for more
usage information.
```rust
extern crate libusb1_sys as ffi;
fn main() {
let version = unsafe { ffi::libusb_get_version() };
println!("libusb v{}.{}.{}.{}", version.major, version.minor, version.micro, version.nano);
}
```
### Native dependencies
`libusb1-sys` exports [metadata] so that dependent crates can find the correct `libusb.h` header
and compile native code that depends on `libusb`. If a crate has a direct dependency on `libusb1-sys`,
its build script has access to the following environment variables:
* `DEP_USB_1.0_INCLUDE` contains the include path with the correct `libusb.h`
* `DEP_USB_1.0_VENDORED` is set with a value of `1` if `libusb1-sys` compiled and linked to
its vendored copy of `libusb`
* `DEP_USB_1.0_STATIC` is set with a value of `1` if static linkage has been used instead of
dynamic.
[metadata]: https://doc.rust-lang.org/cargo/reference/build-scripts.html#the-links-manifest-key
### Finding Help
Since `libusb1-sys` is no more than a wrapper around the native `libusb` library, the best source for
help is the information already available for `libusb`:
* [Home Page](http://libusb.info/)
* [API Documentation](http://libusb.sourceforge.net/api-1.0/)
* [Source](https://github.com/libusb/libusb)
## License
Distributed under the [MIT License](LICENSE).
### License note.
If you link native `libusb` library statically then you must follow [GNU LGPL](https://github.com/libusb/libusb/blob/master/COPYING) from libusb.
+224
View File
@@ -0,0 +1,224 @@
use std::{env, fs, path::PathBuf};
static VERSION: &str = "1.0.30";
fn link(name: &str, bundled: bool) {
use std::env::var;
let target = var("TARGET").unwrap();
let target: Vec<_> = target.split('-').collect();
if target.get(2) == Some(&"windows") {
println!("cargo:rustc-link-lib=dylib={}", name);
if bundled && target.get(3) == Some(&"gnu") {
let dir = var("CARGO_MANIFEST_DIR").unwrap();
println!("cargo:rustc-link-search=native={}/{}", dir, target[0]);
}
}
}
pub fn link_framework(name: &str) {
println!("cargo:rustc-link-lib=framework={}", name);
}
fn get_macos_major_version() -> Option<usize> {
if !cfg!(target_os = "macos") {
return None;
}
let output = std::process::Command::new("sw_vers")
.args(["-productVersion"])
.output()
.unwrap();
let version = std::str::from_utf8(&output.stdout).unwrap().trim_end();
let components: Vec<&str> = version.split('.').collect();
let major: usize = components[0].parse().unwrap();
Some(major)
}
fn find_libusb_pkg(statik: bool) -> bool {
if std::env::var("CARGO_CFG_TARGET_ENV") == Ok("msvc".into()) {
#[cfg(target_os = "windows")]
return match vcpkg::Config::new().find_package("libusb") {
Ok(_) => true,
Err(e) => {
if pkg_config::probe_library("libusb-1.0").is_ok() {
true
} else {
println!("Can't find libusb pkg: {:?}", e);
false
}
}
};
}
// https://github.com/rust-lang/rust/issues/96943
let needs_rustc_issue_96943_workaround: bool = get_macos_major_version()
.map(|major| major >= 11)
.unwrap_or_default();
match pkg_config::Config::new().statik(statik).probe("libusb-1.0") {
Ok(l) => {
for lib in l.libs {
if statik {
if needs_rustc_issue_96943_workaround && lib == "objc" {
continue;
}
println!("cargo:rustc-link-lib=static={}", lib);
}
}
// Provide metadata and include directory for dependencies
if statik {
println!("cargo:static=1");
}
assert!(l.include_paths.len() <= 1); // Cannot have multiple env vars with same name
for path in l.include_paths {
println!("cargo:include={}", path.to_str().unwrap());
}
println!("cargo:version_number={}", l.version);
true
}
Err(e) => {
println!("Can't find libusb pkg: {:?}", e);
false
}
}
}
fn make_source() {
let libusb_source = PathBuf::from("libusb");
/*
Example environment variables and values:
CARGO_CFG_TARGET_ARCH: aarch64
CARGO_CFG_TARGET_ENDIAN: little
CARGO_CFG_TARGET_ENV:
CARGO_CFG_TARGET_FAMILY: unix
CARGO_CFG_TARGET_OS: android
CARGO_CFG_TARGET_POINTER_WIDTH: 64
CARGO_CFG_TARGET_VENDOR: unknown
CARGO_CFG_UNIX:
*/
// Provide metadata and include directory for dependencies
println!("cargo:vendored=1");
println!("cargo:static=1");
let include_dir = PathBuf::from(env::var("OUT_DIR").unwrap()).join("include");
fs::create_dir_all(&include_dir).unwrap();
fs::copy(
libusb_source.join("libusb/libusb.h"),
include_dir.join("libusb.h"),
)
.unwrap();
println!("cargo:include={}", include_dir.to_str().unwrap());
fs::File::create(format!("{}/{}", include_dir.display(), "config.h")).unwrap();
let mut base_config = cc::Build::new();
base_config.include(&include_dir);
base_config.include(libusb_source.join("libusb"));
base_config.define("PRINTF_FORMAT(a, b)", Some(""));
base_config.define("ENABLE_LOGGING", Some("1"));
if std::env::var("CARGO_CFG_TARGET_ENV") == Ok("msvc".into()) {
fs::copy(
libusb_source.join("msvc/config.h"),
include_dir.join("config.h"),
)
.unwrap();
}
if std::env::var("CARGO_CFG_TARGET_OS") == Ok("macos".into()) {
base_config.define("OS_DARWIN", Some("1"));
base_config.define("TARGET_OS_OSX", Some("1"));
base_config.file(libusb_source.join("libusb/os/darwin_usb.c"));
link_framework("CoreFoundation");
link_framework("IOKit");
link_framework("Security");
link("objc", false);
}
if std::env::var("CARGO_CFG_TARGET_OS") == Ok("linux".into())
|| std::env::var("CARGO_CFG_TARGET_OS") == Ok("android".into())
{
base_config.define("OS_LINUX", Some("1"));
base_config.define("HAVE_ASM_TYPES_H", Some("1"));
base_config.define("_GNU_SOURCE", Some("1"));
base_config.define("HAVE_TIMERFD", Some("1"));
base_config.define("HAVE_EVENTFD", Some("1"));
base_config.file(libusb_source.join("libusb/os/linux_netlink.c"));
base_config.file(libusb_source.join("libusb/os/linux_usbfs.c"));
}
if std::env::var("CARGO_CFG_TARGET_FAMILY") == Ok("unix".into()) {
base_config.define("HAVE_SYS_TIME_H", Some("1"));
base_config.define("HAVE_NFDS_T", Some("1"));
base_config.define("PLATFORM_POSIX", Some("1"));
base_config.define("HAVE_CLOCK_GETTIME", Some("1"));
base_config.define(
"DEFAULT_VISIBILITY",
Some("__attribute__((visibility(\"default\")))"),
);
if let Ok(lib) = pkg_config::probe_library("libudev") {
base_config.define("USE_UDEV", Some("1"));
base_config.define("HAVE_LIBUDEV", Some("1"));
base_config.file(libusb_source.join("libusb/os/linux_udev.c"));
for path in lib.include_paths {
base_config.include(path.to_str().unwrap());
}
};
println!("Including posix!");
base_config.file(libusb_source.join("libusb/os/events_posix.c"));
base_config.file(libusb_source.join("libusb/os/threads_posix.c"));
}
if std::env::var("CARGO_CFG_TARGET_OS") == Ok("windows".into()) {
if std::env::var("CARGO_CFG_TARGET_ENV") == Ok("msvc".into()) {
base_config.flag("/source-charset:utf-8");
}
base_config.warnings(false);
base_config.define("OS_WINDOWS", Some("1"));
base_config.file(libusb_source.join("libusb/os/events_windows.c"));
base_config.file(libusb_source.join("libusb/os/threads_windows.c"));
base_config.file(libusb_source.join("libusb/os/windows_common.c"));
base_config.file(libusb_source.join("libusb/os/windows_usbdk.c"));
base_config.file(libusb_source.join("libusb/os/windows_winusb.c"));
base_config.define("DEFAULT_VISIBILITY", Some(""));
base_config.define("PLATFORM_WINDOWS", Some("1"));
link("user32", false);
}
base_config.file(libusb_source.join("libusb/core.c"));
base_config.file(libusb_source.join("libusb/descriptor.c"));
base_config.file(libusb_source.join("libusb/hotplug.c"));
base_config.file(libusb_source.join("libusb/io.c"));
base_config.file(libusb_source.join("libusb/strerror.c"));
base_config.file(libusb_source.join("libusb/sync.c"));
base_config.compile("usb-vendored");
println!("cargo:version_number={}", VERSION);
}
fn main() {
println!("cargo:rerun-if-env-changed=LIBUSB_STATIC");
let statik = {
if cfg!(target_os = "macos") {
match std::env::var("LIBUSB_STATIC").unwrap_or_default().as_ref() {
"" | "0" => false,
_ => true,
}
} else {
std::env::var("CARGO_CFG_TARGET_FEATURE")
.map(|s| s.contains("crt-static"))
.unwrap_or_default()
}
};
let is_freebsd = std::env::var("CARGO_CFG_TARGET_OS") == Ok("freebsd".into());
if (!is_freebsd && cfg!(feature = "vendored")) || !find_libusb_pkg(statik) {
make_source();
}
}
+245
View File
@@ -0,0 +1,245 @@
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 Bertrand
Adrien Destugues
Akshay Jaggi
Alan Ott
Alan Stern
Aleksandr Mezin
Alexander Mot
Alexander Pyhalov
Alexander Schlarb
Alexander Stein
Alex Birkett
Alex Feinman
Alex Vatchenko
Andrew Aldridge
Andrew Fernandes
Andrew Goodney
Andy Chunyu
Andy McFadden
Angus Gratton
Anil Nair
Ankur Verma
Anthony Clay
Antoine Moreau
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
Fabien Sanglard
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
Hannes Franke
Hans Ulrich Niedermann
Harry Mallon
Hartwig Wiesmann
Hector Martin
Hoi-Ho Chan
Ido Yariv
Igor Anokhin
Ihor Dutchak
Ilya Konstantinov
Ingvar Stepanyan
Jakub Klama
James Hanko
Jeffrey Nichols
Jesse Taube
Jie Zhang
Jim Chen
Johann Richard
John Keeping
John Sheu
Jon Beniston
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
Logan Gallois
Lonnie Abelbeck
Luca Longinotti
Luz Paz
Łukasz Bartosik
Mac Wang
Marco Trevisan (Treviño)
Marcus Meissner
Mario Kleiner
Mark Kuo
Mark Lee
Markus Heidelberg
Martin Ettl
Martin Koegler
Martin Ling
Martin Thierer
Mathias Hjärtström
Matt Liberty
Matthew Stapleton
Matthias Bolte
Matthijs Lavrijsen
Michael Dickens
Michel Zou
Mike Frysinger
Mikhail Gusarov
Mikolaj Kucharski
Morgan Leborgne
Moritz Fischer
Nancy Li
Nia Alarie
Nicholas Corgan
Nicolas Bats
Niklas Gürtler
Ole André Vadla Ravnås
Oleksand Radovenchyk
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
Radu Vele
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
Theodor Engøy
Thomas Röfer
Tim Hutt
Tim Roberts
Tobias Klauser
Toby Peterson
Tormod Volden
Trygve Laugstøl
Uri Lublin
Uwe Bonnes
Vadim Mikhailov
Vasily Khoruzhick
Vegard Storheil Eriksen
Venkatesh Shukla
Vianney le Clément de Saint-Marcq
Victor Toso
Vinicius Tinti
Vitali Lovich
Vladimir Beloborodov
Vladimir Gladkov
William Orr
William Skellenger
Xiaofan Chen
Yegor Yefremov
Yiwei Lin
Zeng Guang
Zhiqiang Liu
Zoltán Kovács
Сергей Валерьевич
Ларионов Даниил
Роман Донченко
jonner
orbitcowboy
osy
parafin
RipleyTom
Seneral
saur0n
SomeAlphabetGuy
winterrace
xloem
+504
View 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!
+32
View File
@@ -0,0 +1,32 @@
# 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).
libusb is abstracted internally in such a way that it can hopefully
be ported to other operating systems. Please see the PORTING
file for more information.
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
- Tormod Volden
- Sylvain Fasel
- Sean McBride
- Nathan Hjelm
- Xiaofan Chen
- Hans de Goede
- Ludovic Rousseau
- Chris Dickens
(Please use the mailing list rather than mailing developers directly)
+33
View File
@@ -0,0 +1,33 @@
# libusb
[![Build Status](https://travis-ci.org/libusb/libusb.svg?branch=master)](https://travis-ci.org/libusb/libusb)
[![Build Status](https://ci.appveyor.com/api/projects/status/xvrfam94jii4a6lw?svg=true)](https://ci.appveyor.com/project/LudovicRousseau/libusb)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/2180/badge.svg)](https://scan.coverity.com/projects/libusb-libusb)
libusb is a library for USB device access from Linux, macOS,
Windows, OpenBSD/NetBSD, Haiku, 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)
@@ -0,0 +1,102 @@
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 LIBUSB_WINDOWS_HOTPLUG
OS_WINDOWS_SRC += os/windows_hotplug.h os/windows_hotplug.c
endif
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
@@ -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
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -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;
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,209 @@
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_endpoint_set_raw_io
libusb_endpoint_set_raw_io@12 = libusb_endpoint_set_raw_io
libusb_endpoint_supports_raw_io
libusb_endpoint_supports_raw_io@8 = libusb_endpoint_supports_raw_io
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_device_string
libusb_get_device_string@16 = libusb_get_device_string
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_max_raw_io_transfer_size
libusb_get_max_raw_io_transfer_size@8 = libusb_get_max_raw_io_transfer_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_session_data
libusb_get_session_data@4 = libusb_get_session_data
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
@@ -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
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,158 @@
/*
* 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;
atomic_bool in_reenumerate;
int capture_count;
};
struct darwin_device_priv {
struct darwin_cached_device *dev;
};
struct darwin_interface {
usb_interface_t interface;
uint8_t num_endpoints;
CFRunLoopSourceRef cfSource;
uint64_t frames[256];
uint8_t endpoint_addrs[USB_MAXENDPOINTS];
};
struct darwin_device_handle_priv {
bool is_open;
CFRunLoopSourceRef cfSource;
struct darwin_interface 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
@@ -0,0 +1,896 @@
/*
* 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++) {
// Read descriptor header first to discover target length.
auto config_header_result = co_await_try(
requestDescriptor(LIBUSB_DT_CONFIG, j, LIBUSB_DT_CONFIG_SIZE));
if (auto error = getTransferStatus(config_header_result)) {
co_return error;
}
union usbi_config_desc_buf config_header = {};
copyFromDataView(config_header.buf, config_header_result["data"]);
if (config_header.desc.bDescriptorType != LIBUSB_DT_CONFIG ||
config_header.desc.bLength < LIBUSB_DT_CONFIG_SIZE) {
co_return LIBUSB_ERROR_IO;
}
auto config_total_length =
libusb_le16_to_cpu(config_header.desc.wTotalLength);
if (config_total_length < LIBUSB_DT_CONFIG_SIZE) {
co_return LIBUSB_ERROR_IO;
}
auto config_result = co_await_try(
requestDescriptor(LIBUSB_DT_CONFIG, j, config_total_length));
if (auto error = getTransferStatus(config_result)) {
co_return error;
}
auto configVal = config_result["data"];
if (configVal["byteLength"].as<size_t>() < config_total_length) {
co_return LIBUSB_ERROR_IO;
}
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;
usbi_connect_device(dev);
}
*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("selectConfiguration", 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
@@ -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;
}
@@ -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
@@ -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;
}
@@ -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
@@ -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;
}
}
@@ -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;
};
@@ -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;
}
@@ -0,0 +1,235 @@
/*
* 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,
/*.get_device_string =*/ 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,
/*.endpoint_supports_raw_io =*/ NULL,
/*.endpoint_set_raw_io =*/ NULL,
/*.get_max_raw_io_transfer_size =*/ 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 *),
};
@@ -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_
@@ -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);
}
@@ -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);
}
File diff suppressed because it is too large. Load diff
@@ -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
@@ -0,0 +1,619 @@
/*
* 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;
usbi_connect_device(dev);
}
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;
}
@@ -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,
};
@@ -0,0 +1,702 @@
/*
* 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;
}
usbi_connect_device(dev);
}
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);
}
File diff suppressed because it is too large. Load diff
@@ -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 */
@@ -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(usbi_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(usbi_cond_t *cond,
usbi_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;
}
@@ -0,0 +1,104 @@
/*
* 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)
{
int mutexIsLocked = pthread_mutex_trylock(mutex) == 0;
return mutexIsLocked;
}
static inline void usbi_mutex_destroy(usbi_mutex_t *mutex)
{
PTHREAD_CHECK(pthread_mutex_destroy(mutex));
}
#define USBI_COND_INITIALIZER PTHREAD_COND_INITIALIZER
typedef pthread_cond_t usbi_cond_t;
void usbi_cond_init(usbi_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_signal(usbi_cond_t *cond)
{
PTHREAD_CHECK(pthread_cond_signal(cond));
}
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 */
@@ -0,0 +1,40 @@
/*
* libusb synchronization on Microsoft Windows
*
* Copyright © 2010 Michael Plante <michael.plante@gmail.com>
* Copyright © 2020 Chris Dickens <christopher.a.dickens@gmail.com>
*
* This library is free software; you can redistribute it and/or
* 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"
int usbi_cond_timedwait(usbi_cond_t *cond,
usbi_mutex_t *mutex, const struct timeval *tv)
{
DWORD millis;
millis = (DWORD)(tv->tv_sec * 1000L) + (tv->tv_usec / 1000L);
/* round up to next millisecond */
if (tv->tv_usec % 1000L)
millis++;
if (SleepConditionVariableCS(cond, mutex, millis))
return 0;
else if (GetLastError() == ERROR_TIMEOUT)
return LIBUSB_ERROR_TIMEOUT;
else
return LIBUSB_ERROR_OTHER;
}
@@ -0,0 +1,114 @@
/*
* libusb synchronization on Microsoft Windows
*
* Copyright © 2010 Michael Plante <michael.plante@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_THREADS_WINDOWS_H
#define LIBUSB_THREADS_WINDOWS_H
#define WINAPI_CHECK(expression) ASSERT_NE(expression, 0)
#define USBI_MUTEX_INITIALIZER 0L
typedef LONG usbi_mutex_static_t;
static inline void usbi_mutex_static_lock(usbi_mutex_static_t *mutex)
{
while (InterlockedExchange(mutex, 1L) == 1L)
SleepEx(0, TRUE);
}
static inline void usbi_mutex_static_unlock(usbi_mutex_static_t *mutex)
{
InterlockedExchange(mutex, 0L);
}
typedef CRITICAL_SECTION usbi_mutex_t;
static inline void usbi_mutex_init(usbi_mutex_t *mutex)
{
InitializeCriticalSection(mutex);
}
static inline void usbi_mutex_lock(usbi_mutex_t *mutex)
{
EnterCriticalSection(mutex);
}
static inline void usbi_mutex_unlock(usbi_mutex_t *mutex)
{
LeaveCriticalSection(mutex);
}
static inline int usbi_mutex_trylock(usbi_mutex_t *mutex)
{
int mutexIsLocked = TryEnterCriticalSection(mutex) != 0;
return mutexIsLocked;
}
static inline void usbi_mutex_destroy(usbi_mutex_t *mutex)
{
DeleteCriticalSection(mutex);
}
#if !defined(HAVE_STRUCT_TIMESPEC) && !defined(_TIMESPEC_DEFINED)
#define HAVE_STRUCT_TIMESPEC 1
#define _TIMESPEC_DEFINED 1
struct timespec {
long tv_sec;
long tv_nsec;
};
#endif /* HAVE_STRUCT_TIMESPEC || _TIMESPEC_DEFINED */
typedef CONDITION_VARIABLE usbi_cond_t;
static inline void usbi_cond_init(usbi_cond_t *cond)
{
InitializeConditionVariable(cond);
}
static inline void usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex)
{
WINAPI_CHECK(SleepConditionVariableCS(cond, mutex, INFINITE));
}
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)
{
WakeAllConditionVariable(cond);
}
static inline void usbi_cond_destroy(usbi_cond_t *cond)
{
UNUSED(cond);
}
typedef DWORD usbi_tls_key_t;
static inline void usbi_tls_key_create(usbi_tls_key_t *key)
{
*key = TlsAlloc();
assert(*key != TLS_OUT_OF_INDEXES);
}
static inline void *usbi_tls_key_get(usbi_tls_key_t key)
{
return TlsGetValue(key);
}
static inline void usbi_tls_key_set(usbi_tls_key_t key, void *ptr)
{
WINAPI_CHECK(TlsSetValue(key, ptr));
}
static inline void usbi_tls_key_delete(usbi_tls_key_t key)
{
WINAPI_CHECK(TlsFree(key));
}
static inline unsigned long usbi_get_tid(void)
{
return (unsigned long)GetCurrentThreadId();
}
#endif /* LIBUSB_THREADS_WINDOWS_H */
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,443 @@
/*
* Windows backend common header for libusb 1.0
*
* This file brings together header code common between
* the desktop Windows backends.
* Copyright © 2012-2013 RealVNC Ltd.
* Copyright © 2009-2012 Pete Batard <pete@akeo.ie>
* Copyright © 2014-2020 Chris Dickens <christopher.a.dickens@gmail.com>
* With contributions from Michael Plante, Orin Eman et al.
* Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
* Major code testing contribution by Xiaofan Chen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef LIBUSB_WINDOWS_COMMON_H
#define LIBUSB_WINDOWS_COMMON_H
#include <stdbool.h>
/*
* Workaround for the mess that exists with the DWORD and ULONG types.
* Visual Studio unconditionally defines these types as 'unsigned long'
* and a long is always 32-bits, even on 64-bit builds. GCC on the other
* hand varies the width of a long, matching it to the build. To make
* matters worse, the platform headers for these GCC builds define a
* DWORD/ULONG to be 'unsigned long' on 32-bit builds and 'unsigned int'
* on 64-bit builds. This creates a great deal of warnings for compilers
* that support printf format checking since it will never actually be
* an unsigned long.
*/
#if defined(_MSC_VER)
#define ULONG_CAST(x) (x)
#else
#define ULONG_CAST(x) ((unsigned long)(x))
#endif
#if defined(__CYGWIN__)
#define _stricmp strcasecmp
#define _strdup strdup
// _beginthreadex is MSVCRT => unavailable for cygwin. Fallback to using CreateThread
#define _beginthreadex(a, b, c, d, e, f) CreateThread(a, b, (LPTHREAD_START_ROUTINE)c, d, e, (LPDWORD)f)
#else
#include <process.h>
#endif
#define safe_free(p) do {if (p != NULL) {free((void *)p); p = NULL;}} while (0)
/*
* API macros - leveraged from libusb-win32 1.x
*/
#define DLL_STRINGIFY(s) #s
/*
* Macros for handling DLL themselves
*/
#define DLL_HANDLE_NAME(name) __dll_##name##_handle
#define DLL_DECLARE_HANDLE(name) \
static HMODULE DLL_HANDLE_NAME(name)
#define DLL_GET_HANDLE(ctx, name) \
do { \
DLL_HANDLE_NAME(name) = load_system_library(ctx, \
DLL_STRINGIFY(name)); \
if (!DLL_HANDLE_NAME(name)) \
return false; \
} while (0)
#define DLL_FREE_HANDLE(name) \
do { \
if (DLL_HANDLE_NAME(name)) { \
FreeLibrary(DLL_HANDLE_NAME(name)); \
DLL_HANDLE_NAME(name) = NULL; \
} \
} while (0)
/*
* Macros for handling functions within a DLL
*/
#define DLL_FUNC_NAME(name) __dll_##name##_func_t
#define DLL_DECLARE_FUNC_PREFIXNAME(api, ret, prefixname, name, args) \
typedef ret (api * DLL_FUNC_NAME(name))args; \
static DLL_FUNC_NAME(name) prefixname
#define DLL_DECLARE_FUNC(api, ret, name, args) \
DLL_DECLARE_FUNC_PREFIXNAME(api, ret, name, name, args)
#define DLL_DECLARE_FUNC_PREFIXED(api, ret, prefix, name, args) \
DLL_DECLARE_FUNC_PREFIXNAME(api, ret, prefix##name, name, args)
#define DLL_LOAD_FUNC_PREFIXNAME(dll, prefixname, name, ret_on_failure) \
do { \
HMODULE h = DLL_HANDLE_NAME(dll); \
prefixname = (DLL_FUNC_NAME(name))GetProcAddress(h, \
DLL_STRINGIFY(name)); \
if (prefixname) \
break; \
prefixname = (DLL_FUNC_NAME(name))GetProcAddress(h, \
DLL_STRINGIFY(name) DLL_STRINGIFY(A)); \
if (prefixname) \
break; \
prefixname = (DLL_FUNC_NAME(name))GetProcAddress(h, \
DLL_STRINGIFY(name) DLL_STRINGIFY(W)); \
if (prefixname) \
break; \
if (ret_on_failure) \
return false; \
} while (0)
#define DLL_LOAD_FUNC(dll, name, ret_on_failure) \
DLL_LOAD_FUNC_PREFIXNAME(dll, name, name, ret_on_failure)
#define DLL_LOAD_FUNC_PREFIXED(dll, prefix, name, ret_on_failure) \
DLL_LOAD_FUNC_PREFIXNAME(dll, prefix##name, name, ret_on_failure)
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff539136(v=vs.85).aspx
#if !defined(USBD_SUCCESS)
typedef LONG USBD_STATUS;
#define USBD_SUCCESS(Status) ((USBD_STATUS)(Status) >= 0)
#define USBD_STATUS_STALL_PID ((USBD_STATUS)0xC0000004L)
#define USBD_STATUS_ENDPOINT_HALTED ((USBD_STATUS)0xC0000030L)
#define USBD_STATUS_TIMEOUT ((USBD_STATUS)0xC0006000L)
#define USBD_STATUS_DEVICE_GONE ((USBD_STATUS)0xC0007000L)
#define USBD_STATUS_CANCELED ((USBD_STATUS)0xC0010000L)
#endif
// error code added with Windows SDK 10.0.18362
#ifndef ERROR_NO_SUCH_DEVICE
#define ERROR_NO_SUCH_DEVICE 433L
#endif
/* Windows versions */
enum windows_version {
WINDOWS_UNDEFINED,
WINDOWS_2000,
WINDOWS_XP,
WINDOWS_2003, // Also XP x64
WINDOWS_VISTA,
WINDOWS_7,
WINDOWS_8,
WINDOWS_8_1,
WINDOWS_10,
WINDOWS_11,
WINDOWS_12_OR_LATER
};
extern enum windows_version windows_version;
#include <pshpack1.h>
typedef struct USB_DEVICE_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
USHORT bcdUSB;
UCHAR bDeviceClass;
UCHAR bDeviceSubClass;
UCHAR bDeviceProtocol;
UCHAR bMaxPacketSize0;
USHORT idVendor;
USHORT idProduct;
USHORT bcdDevice;
UCHAR iManufacturer;
UCHAR iProduct;
UCHAR iSerialNumber;
UCHAR bNumConfigurations;
} USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;
typedef struct USB_CONFIGURATION_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
USHORT wTotalLength;
UCHAR bNumInterfaces;
UCHAR bConfigurationValue;
UCHAR iConfiguration;
UCHAR bmAttributes;
UCHAR MaxPower;
} USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR;
#include <poppack.h>
#define MAX_DEVICE_ID_LEN 200
typedef struct USB_DK_DEVICE_ID {
WCHAR DeviceID[MAX_DEVICE_ID_LEN];
WCHAR InstanceID[MAX_DEVICE_ID_LEN];
} USB_DK_DEVICE_ID, *PUSB_DK_DEVICE_ID;
typedef struct USB_DK_DEVICE_INFO {
USB_DK_DEVICE_ID ID;
ULONG64 FilterID;
ULONG64 Port;
ULONG64 Speed;
USB_DEVICE_DESCRIPTOR DeviceDescriptor;
} USB_DK_DEVICE_INFO, *PUSB_DK_DEVICE_INFO;
typedef struct USB_DK_ISO_TRANSFER_RESULT {
ULONG64 ActualLength;
ULONG64 TransferResult;
} USB_DK_ISO_TRANSFER_RESULT, *PUSB_DK_ISO_TRANSFER_RESULT;
typedef struct USB_DK_GEN_TRANSFER_RESULT {
ULONG64 BytesTransferred;
ULONG64 UsbdStatus; // USBD_STATUS code
} USB_DK_GEN_TRANSFER_RESULT, *PUSB_DK_GEN_TRANSFER_RESULT;
typedef struct USB_DK_TRANSFER_RESULT {
USB_DK_GEN_TRANSFER_RESULT GenResult;
PVOID64 IsochronousResultsArray; // array of USB_DK_ISO_TRANSFER_RESULT
} USB_DK_TRANSFER_RESULT, *PUSB_DK_TRANSFER_RESULT;
typedef struct USB_DK_TRANSFER_REQUEST {
ULONG64 EndpointAddress;
PVOID64 Buffer;
ULONG64 BufferLength;
ULONG64 TransferType;
ULONG64 IsochronousPacketsArraySize;
PVOID64 IsochronousPacketsArray;
USB_DK_TRANSFER_RESULT Result;
} USB_DK_TRANSFER_REQUEST, *PUSB_DK_TRANSFER_REQUEST;
struct usbdk_device_priv {
USB_DK_DEVICE_ID ID;
PUSB_CONFIGURATION_DESCRIPTOR *config_descriptors;
HANDLE redirector_handle;
HANDLE system_handle;
uint8_t active_configuration;
};
struct winusb_device_priv {
bool initialized;
#if defined(LIBUSB_WINDOWS_HOTPLUG)
bool seen_during_scan; // set true for each device encountered during windows_get_device_list
bool seen_before_scan; // set true for each device encountered before windows_get_device_list
#endif
bool root_hub;
uint8_t active_config;
uint16_t langid; // cached USB language ID for string descriptor requests
uint8_t depth; // distance to HCD
const struct windows_usb_api_backend *apib;
char *dev_id;
char *path; // device interface path
int sub_api; // for WinUSB-like APIs
usbi_mutex_t interface_lock; // protects usb_interface[] against concurrent
// claim/release/altsetting from different handles,
// and concurrent enumeration setup
// (set_composite_interface, set_hid_interface,
// and HUB_PASS/DEV_PASS in winusb_get_device_list)
struct {
char *path; // each interface needs a device interface path,
const struct windows_usb_api_backend *apib; // an API backend (multiple drivers support),
int sub_api;
int8_t nb_endpoints; // and a set of endpoint addresses (USB_MAXENDPOINTS)
uint8_t *endpoint;
int current_altsetting;
bool restricted_functionality; // indicates if the interface functionality is restricted
// by Windows (eg. HID keyboards or mice cannot do R/W)
uint8_t num_associated_interfaces; // If non-zero, the interface is part of a grouped
// set of associated interfaces (defined by an IAD)
// and this is the number of interfaces within the
// associated group (bInterfaceCount in IAD).
uint8_t first_associated_interface; // For associated interfaces, this is the index of
// the first interface (bFirstInterface in IAD) for
// the grouped set of associated interfaces.
} usb_interface[USB_MAXINTERFACES];
struct hid_device_priv *hid;
PUSB_CONFIGURATION_DESCRIPTOR *config_descriptor; // list of pointers to the cached config descriptors
GUID class_guid; // checked for change during re-enumeration
};
struct usbdk_device_handle_priv {
// Not currently used
char dummy;
};
enum WINUSB_ZLP {
WINUSB_ZLP_UNSET = 0,
WINUSB_ZLP_OFF = 1,
WINUSB_ZLP_ON = 2
};
struct winusb_device_handle_priv {
int active_interface;
struct {
HANDLE dev_handle; // WinUSB needs an extra handle for the file
HANDLE api_handle; // used by the API to communicate with the device
uint8_t zlp[USB_MAXENDPOINTS]; // Current per-endpoint SHORT_PACKET_TERMINATE status (enum WINUSB_ZLP)
} interface_handle[USB_MAXINTERFACES];
int autoclaim_count[USB_MAXINTERFACES]; // For auto-release
};
struct usbdk_transfer_priv {
USB_DK_TRANSFER_REQUEST request;
PULONG64 IsochronousPacketsArray;
PUSB_DK_ISO_TRANSFER_RESULT IsochronousResultsArray;
};
struct winusb_transfer_priv {
uint8_t interface_number;
uint8_t *hid_buffer; // 1 byte extended data buffer, required for HID
uint8_t *hid_dest; // transfer buffer destination, required for HID
size_t hid_expected_size;
// For isochronous transfers with LibUSBk driver:
void *iso_context;
// For isochronous transfers with Microsoft WinUSB driver:
void *isoch_buffer_handle; // The isoch_buffer_handle to free at the end of the transfer
BOOL iso_break_stream; // Whether the isoch. stream was to be continued in the last call of libusb_submit_transfer.
// As we this structure is zeroed out upon initialization, we need to use inverse logic here.
libusb_transfer_cb_fn iso_user_callback; // Original transfer callback of the user. Might be used for isochronous transfers.
};
struct windows_backend {
int (*init)(struct libusb_context *ctx);
void (*exit)(struct libusb_context *ctx);
int (*get_device_list)(struct libusb_context *ctx,
struct discovered_devs **discdevs);
int (*get_device_string)(libusb_device *dev,
enum libusb_device_string_type string_type, char *data, int length);
int (*open)(struct libusb_device_handle *dev_handle);
void (*close)(struct libusb_device_handle *dev_handle);
int (*get_active_config_descriptor)(struct libusb_device *device,
void *buffer, size_t len);
int (*get_config_descriptor)(struct libusb_device *device,
uint8_t config_index, void *buffer, size_t len);
int (*get_config_descriptor_by_value)(struct libusb_device *device,
uint8_t bConfigurationValue, void **buffer);
int (*get_configuration)(struct libusb_device_handle *dev_handle, uint8_t *config);
int (*set_configuration)(struct libusb_device_handle *dev_handle, uint8_t config);
int (*claim_interface)(struct libusb_device_handle *dev_handle, uint8_t interface_number);
int (*release_interface)(struct libusb_device_handle *dev_handle, uint8_t interface_number);
int (*set_interface_altsetting)(struct libusb_device_handle *dev_handle,
uint8_t interface_number, uint8_t altsetting);
int (*clear_halt)(struct libusb_device_handle *dev_handle,
unsigned char endpoint);
int (*reset_device)(struct libusb_device_handle *dev_handle);
void (*destroy_device)(struct libusb_device *dev);
int (*submit_transfer)(struct usbi_transfer *itransfer);
int (*cancel_transfer)(struct usbi_transfer *itransfer);
void (*clear_transfer_priv)(struct usbi_transfer *itransfer);
enum libusb_transfer_status (*copy_transfer_data)(struct usbi_transfer *itransfer, DWORD length);
int (*endpoint_supports_raw_io)(struct libusb_device_handle *dev_handle,
uint8_t endpoint);
int (*endpoint_set_raw_io)(struct libusb_device_handle *dev_handle,
uint8_t endpoint, int enable);
int (*get_max_raw_io_transfer_size)(
struct libusb_device_handle *dev_handle,
uint8_t endpoint);
};
struct windows_context_priv {
const struct windows_backend *backend;
HANDLE completion_port;
HANDLE completion_port_thread;
};
union windows_device_priv {
struct usbdk_device_priv usbdk_priv;
struct winusb_device_priv winusb_priv;
};
struct windows_device_handle_priv {
struct list_head active_transfers;
union {
struct usbdk_device_handle_priv usbdk_priv;
struct winusb_device_handle_priv winusb_priv;
};
};
struct windows_transfer_priv {
OVERLAPPED overlapped;
HANDLE handle;
struct list_head list;
union {
struct usbdk_transfer_priv usbdk_priv;
struct winusb_transfer_priv winusb_priv;
};
};
static inline struct usbdk_device_handle_priv *get_usbdk_device_handle_priv(struct libusb_device_handle *dev_handle)
{
struct windows_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle);
return &handle_priv->usbdk_priv;
}
static inline struct winusb_device_handle_priv *get_winusb_device_handle_priv(struct libusb_device_handle *dev_handle)
{
struct windows_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle);
return &handle_priv->winusb_priv;
}
static inline OVERLAPPED *get_transfer_priv_overlapped(struct usbi_transfer *itransfer)
{
struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
return &transfer_priv->overlapped;
}
static inline void set_transfer_priv_handle(struct usbi_transfer *itransfer, HANDLE handle)
{
struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
transfer_priv->handle = handle;
}
static inline struct usbdk_transfer_priv *get_usbdk_transfer_priv(struct usbi_transfer *itransfer)
{
struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
return &transfer_priv->usbdk_priv;
}
static inline struct winusb_transfer_priv *get_winusb_transfer_priv(struct usbi_transfer *itransfer)
{
struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
return &transfer_priv->winusb_priv;
}
extern const struct windows_backend usbdk_backend;
extern const struct windows_backend winusb_backend;
HMODULE load_system_library(struct libusb_context *ctx, const char *name);
unsigned long htab_hash(const char *str);
enum libusb_transfer_status usbd_status_to_libusb_transfer_status(USBD_STATUS status);
void windows_force_sync_completion(struct usbi_transfer *itransfer, ULONG size);
#if defined(ENABLE_LOGGING)
const char *windows_error_str(DWORD error_code);
#endif
#endif
@@ -0,0 +1,321 @@
/*
* windows hotplug backend for libusb 1.0
* Copyright © 2024 Sylvain Fasel <sylvain@sonatique.net>
*
* 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 "threads_windows.h"
#include "windows_common.h"
#include "windows_hotplug.h"
#include <stdio.h>
#include <dbt.h>
/* The Windows Hotplug system is a two steps process.
* 1. We create a hidden window and listen for DBT_DEVNODES_CHANGED, which Windows
* broadcasts to all top-level windows whenever the device tree changes (no
* registration required). Multiple rapid events (e.g. a hub with many children)
* are coalesced via a short debounce timer so we only scan once the burst settles.
* A maximum delay ceiling guarantees a scan fires within a bounded time even
* during sustained bursts, preventing unbounded latency.
* 2. Upon timer expiry, we snapshot the current device list, run a full re-enumeration
* via the Windows backend, then diff the result: newly found devices that have been
* successfully initialized generate DEVICE_ARRIVED events; devices that were not
* encountered by the re-enumeration (physically removed) generate DEVICE_LEFT events.
*/
#define HOTPLUG_DEBOUNCE_TIMER_ID 1
#define HOTPLUG_DEBOUNCE_MS 10
#define HOTPLUG_DEBOUNCE_MAX_DELAY_MS 100
static ULONGLONG first_debounce_tick;
static HWND windows_event_hwnd;
static HANDLE windows_event_thread_handle;
static DWORD WINAPI windows_event_thread_main(LPVOID lpParam);
static LRESULT CALLBACK windows_proc_callback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
#define log_error(operation) do { \
usbi_err(NULL, "%s failed with error: %s", operation, windows_error_str(0)); \
} while (0)
int windows_start_event_monitor(void)
{
windows_event_thread_handle = CreateThread(
NULL, // Default security descriptor
0, // Default stack size
windows_event_thread_main,
NULL, // No parameters to pass to the thread
0, // Start immediately
NULL // No need to keep track of thread ID
);
if (windows_event_thread_handle == NULL)
{
log_error("CreateThread");
return LIBUSB_ERROR_OTHER;
}
return LIBUSB_SUCCESS;
}
int windows_stop_event_monitor(void)
{
if (windows_event_hwnd == NULL)
{
return LIBUSB_SUCCESS;
}
if (!SUCCEEDED(SendMessage(windows_event_hwnd, WM_CLOSE, 0, 0)))
{
log_error("SendMessage");
return LIBUSB_ERROR_OTHER;
}
if (WaitForSingleObject(windows_event_thread_handle, INFINITE) != WAIT_OBJECT_0)
{
log_error("WaitForSingleObject");
return LIBUSB_ERROR_OTHER;
}
if (!CloseHandle(windows_event_thread_handle))
{
log_error("CloseHandle");
return LIBUSB_ERROR_OTHER;
}
return LIBUSB_SUCCESS;
}
static int windows_get_device_list(struct libusb_context *ctx)
{
// note: context device list is protected by active_contexts_lock
return ((struct windows_context_priv *)usbi_get_context_priv(ctx))->backend->get_device_list(ctx, NULL);
}
void windows_initial_scan_devices(struct libusb_context *ctx)
{
usbi_mutex_static_lock(&active_contexts_lock);
const int ret = windows_get_device_list(ctx);
if (ret != LIBUSB_SUCCESS)
{
usbi_err(ctx, "hotplug failed to retrieve initial list with error: %s", libusb_error_name(ret));
}
usbi_mutex_static_unlock(&active_contexts_lock);
}
static void windows_refresh_device_list(struct libusb_context *ctx)
{
struct libusb_device *dev, *next_dev;
// Step 1: clear seen_during_scan so the scan can mark which devices are still
// physically present, and set seen_before_scan so we can distinguish newly
// created devices (which start with seen_before_scan=false via calloc).
for_each_device_safe(ctx, dev, next_dev)
{
struct winusb_device_priv *priv = (struct winusb_device_priv *)usbi_get_device_priv(dev);
priv->seen_during_scan = false;
priv->seen_before_scan = true;
}
// Step 2: re-enumerate — winusb_get_device_list attaches newly-arrived devices
// and sets seen_during_scan=true for every device it physically encounters.
// seen_before_scan is untouched and will be left in default state (false) for newly created devices, allowing us to identify them in the next step.
const int ret = windows_get_device_list(ctx);
if (ret != LIBUSB_SUCCESS)
{
usbi_err(ctx, "hotplug failed to retrieve current list with error: %s", libusb_error_name(ret));
return;
}
// Step 3: diff old vs new.
for_each_device_safe(ctx, dev, next_dev)
{
struct winusb_device_priv *priv = (struct winusb_device_priv *)usbi_get_device_priv(dev);
if (!priv->seen_during_scan)
{
// Not encountered by the scan: device was physically removed.
if (priv->initialized)
{
usbi_disconnect_device(dev); // fires DEVICE_LEFT
}
else
{
usbi_detach_device(dev);
// No DEVICE_LEFT message is posted for uninitialized
// devices, so no message handler will drop the initial
// ref. We must drop it here to avoid a leak.
libusb_unref_device(dev);
}
}
else if (!priv->seen_before_scan)
{
if (priv->initialized)
{
usbi_hotplug_notification(ctx, dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED);
}
}
}
}
static void windows_refresh_device_list_for_all_ctx(void)
{
usbi_mutex_static_lock(&active_contexts_lock);
struct libusb_context *ctx;
for_each_context(ctx)
{
windows_refresh_device_list(ctx);
}
usbi_mutex_static_unlock(&active_contexts_lock);
}
#define WND_CLASS_NAME TEXT("libusb-1.0-windows-hotplug")
static bool init_wnd_class(void)
{
WNDCLASS wndClass = { 0 };
wndClass.lpfnWndProc = windows_proc_callback;
wndClass.hInstance = GetModuleHandle(NULL);
wndClass.lpszClassName = WND_CLASS_NAME;
if (!RegisterClass(&wndClass))
{
log_error("event thread: RegisterClass");
return false;
}
return true;
}
static DWORD WINAPI windows_event_thread_main(LPVOID lpParam)
{
UNUSED(lpParam);
usbi_dbg(NULL, "windows event thread entering");
if (!init_wnd_class())
{
return (DWORD)-1;
}
windows_event_hwnd = CreateWindow(
WND_CLASS_NAME,
TEXT(""),
0,
0, 0, 0, 0,
NULL, NULL,
GetModuleHandle(NULL),
NULL);
if (windows_event_hwnd == NULL)
{
log_error("event thread: CreateWindow");
return (DWORD)-1;
}
MSG msg;
BOOL ret_val;
while ((ret_val = GetMessage(&msg, windows_event_hwnd, 0, 0)) != 0)
{
if (ret_val == -1)
{
log_error("event thread: GetMessage");
break;
}
if (!SUCCEEDED(TranslateMessage(&msg)))
{
log_error("event thread: TranslateMessage");
}
if (!SUCCEEDED(DispatchMessage(&msg)))
{
log_error("event thread: DispatchMessage");
}
}
usbi_dbg(NULL, "windows event thread exiting");
return 0;
}
static LRESULT CALLBACK windows_proc_callback(
HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
switch (message)
{
case WM_DEVICECHANGE:
if (wParam == DBT_DEVNODES_CHANGED)
{
if (first_debounce_tick == 0)
{
// First event in a new burst — record the time and start the debounce timer.
first_debounce_tick = GetTickCount64();
SetTimer(hwnd, HOTPLUG_DEBOUNCE_TIMER_ID, HOTPLUG_DEBOUNCE_MS, NULL);
}
else if (GetTickCount64() - first_debounce_tick >= HOTPLUG_DEBOUNCE_MAX_DELAY_MS)
{
// Maximum delay reached — force an immediate scan so devices
// are not invisible for the entire duration of a sustained burst.
KillTimer(hwnd, HOTPLUG_DEBOUNCE_TIMER_ID);
first_debounce_tick = 0;
windows_refresh_device_list_for_all_ctx();
}
else
{
// Still within the max-delay window — reset the debounce timer.
SetTimer(hwnd, HOTPLUG_DEBOUNCE_TIMER_ID, HOTPLUG_DEBOUNCE_MS, NULL);
}
return TRUE;
}
return DefWindowProc(hwnd, message, wParam, lParam);
case WM_TIMER:
if (wParam == HOTPLUG_DEBOUNCE_TIMER_ID)
{
KillTimer(hwnd, HOTPLUG_DEBOUNCE_TIMER_ID);
first_debounce_tick = 0;
windows_refresh_device_list_for_all_ctx();
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
case WM_CLOSE:
KillTimer(hwnd, HOTPLUG_DEBOUNCE_TIMER_ID);
first_debounce_tick = 0;
if (!DestroyWindow(hwnd))
{
log_error("DestroyWindow");
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
}
@@ -0,0 +1,28 @@
/*
* windows hotplug backend for libusb 1.0
* Copyright © 2024 Sylvain Fasel <sylvain@sonatique.net>
*
* 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 WINDOWS_HOTPLUG_H
#define WINDOWS_HOTPLUG_H
int windows_start_event_monitor(void);
int windows_stop_event_monitor(void);
void windows_initial_scan_devices(struct libusb_context *ctx);
#endif
@@ -0,0 +1,732 @@
/*
* windows UsbDk backend for libusb 1.0
* Copyright © 2014 Red Hat, Inc.
* Authors:
* Dmitry Fleytman <dmitry@daynix.com>
* Pavel Gurvich <pavel@daynix.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 <windows.h>
#include <stdio.h>
#include "libusbi.h"
#include "windows_usbdk.h"
#if !defined(STATUS_SUCCESS)
typedef LONG NTSTATUS;
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#endif
#if !defined(STATUS_CANCELLED)
#define STATUS_CANCELLED ((NTSTATUS)0xC0000120L)
#endif
#if !defined(STATUS_REQUEST_CANCELED)
#define STATUS_REQUEST_CANCELED ((NTSTATUS)0xC0000703L)
#endif
static struct {
HMODULE module;
USBDK_GET_DEVICES_LIST GetDevicesList;
USBDK_RELEASE_DEVICES_LIST ReleaseDevicesList;
USBDK_START_REDIRECT StartRedirect;
USBDK_STOP_REDIRECT StopRedirect;
USBDK_GET_CONFIGURATION_DESCRIPTOR GetConfigurationDescriptor;
USBDK_RELEASE_CONFIGURATION_DESCRIPTOR ReleaseConfigurationDescriptor;
USBDK_READ_PIPE ReadPipe;
USBDK_WRITE_PIPE WritePipe;
USBDK_ABORT_PIPE AbortPipe;
USBDK_RESET_PIPE ResetPipe;
USBDK_SET_ALTSETTING SetAltsetting;
USBDK_RESET_DEVICE ResetDevice;
USBDK_GET_REDIRECTOR_SYSTEM_HANDLE GetRedirectorSystemHandle;
} usbdk_helper;
static FARPROC get_usbdk_proc_addr(struct libusb_context *ctx, LPCSTR api_name)
{
FARPROC api_ptr = GetProcAddress(usbdk_helper.module, api_name);
if (api_ptr == NULL)
usbi_err(ctx, "UsbDkHelper API %s not found: %s", api_name, windows_error_str(0));
return api_ptr;
}
static void unload_usbdk_helper_dll(void)
{
if (usbdk_helper.module != NULL) {
FreeLibrary(usbdk_helper.module);
usbdk_helper.module = NULL;
}
}
static int load_usbdk_helper_dll(struct libusb_context *ctx)
{
usbdk_helper.module = load_system_library(ctx, "UsbDkHelper");
if (usbdk_helper.module == NULL) {
usbi_err(ctx, "Failed to load UsbDkHelper.dll: %s", windows_error_str(0));
return LIBUSB_ERROR_NOT_FOUND;
}
usbdk_helper.GetDevicesList = (USBDK_GET_DEVICES_LIST)get_usbdk_proc_addr(ctx, "UsbDk_GetDevicesList");
if (usbdk_helper.GetDevicesList == NULL)
goto error_unload;
usbdk_helper.ReleaseDevicesList = (USBDK_RELEASE_DEVICES_LIST)get_usbdk_proc_addr(ctx, "UsbDk_ReleaseDevicesList");
if (usbdk_helper.ReleaseDevicesList == NULL)
goto error_unload;
usbdk_helper.StartRedirect = (USBDK_START_REDIRECT)get_usbdk_proc_addr(ctx, "UsbDk_StartRedirect");
if (usbdk_helper.StartRedirect == NULL)
goto error_unload;
usbdk_helper.StopRedirect = (USBDK_STOP_REDIRECT)get_usbdk_proc_addr(ctx, "UsbDk_StopRedirect");
if (usbdk_helper.StopRedirect == NULL)
goto error_unload;
usbdk_helper.GetConfigurationDescriptor = (USBDK_GET_CONFIGURATION_DESCRIPTOR)get_usbdk_proc_addr(ctx, "UsbDk_GetConfigurationDescriptor");
if (usbdk_helper.GetConfigurationDescriptor == NULL)
goto error_unload;
usbdk_helper.ReleaseConfigurationDescriptor = (USBDK_RELEASE_CONFIGURATION_DESCRIPTOR)get_usbdk_proc_addr(ctx, "UsbDk_ReleaseConfigurationDescriptor");
if (usbdk_helper.ReleaseConfigurationDescriptor == NULL)
goto error_unload;
usbdk_helper.ReadPipe = (USBDK_READ_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_ReadPipe");
if (usbdk_helper.ReadPipe == NULL)
goto error_unload;
usbdk_helper.WritePipe = (USBDK_WRITE_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_WritePipe");
if (usbdk_helper.WritePipe == NULL)
goto error_unload;
usbdk_helper.AbortPipe = (USBDK_ABORT_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_AbortPipe");
if (usbdk_helper.AbortPipe == NULL)
goto error_unload;
usbdk_helper.ResetPipe = (USBDK_RESET_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_ResetPipe");
if (usbdk_helper.ResetPipe == NULL)
goto error_unload;
usbdk_helper.SetAltsetting = (USBDK_SET_ALTSETTING)get_usbdk_proc_addr(ctx, "UsbDk_SetAltsetting");
if (usbdk_helper.SetAltsetting == NULL)
goto error_unload;
usbdk_helper.ResetDevice = (USBDK_RESET_DEVICE)get_usbdk_proc_addr(ctx, "UsbDk_ResetDevice");
if (usbdk_helper.ResetDevice == NULL)
goto error_unload;
usbdk_helper.GetRedirectorSystemHandle = (USBDK_GET_REDIRECTOR_SYSTEM_HANDLE)get_usbdk_proc_addr(ctx, "UsbDk_GetRedirectorSystemHandle");
if (usbdk_helper.GetRedirectorSystemHandle == NULL)
goto error_unload;
return LIBUSB_SUCCESS;
error_unload:
FreeLibrary(usbdk_helper.module);
usbdk_helper.module = NULL;
return LIBUSB_ERROR_NOT_FOUND;
}
typedef SC_HANDLE (WINAPI *POPENSCMANAGERA)(LPCSTR, LPCSTR, DWORD);
typedef SC_HANDLE (WINAPI *POPENSERVICEA)(SC_HANDLE, LPCSTR, DWORD);
typedef BOOL (WINAPI *PCLOSESERVICEHANDLE)(SC_HANDLE);
static int usbdk_init(struct libusb_context *ctx)
{
POPENSCMANAGERA pOpenSCManagerA;
POPENSERVICEA pOpenServiceA;
PCLOSESERVICEHANDLE pCloseServiceHandle;
SC_HANDLE managerHandle;
SC_HANDLE serviceHandle;
HMODULE h;
h = load_system_library(ctx, "Advapi32");
if (h == NULL) {
usbi_warn(ctx, "failed to open Advapi32\n");
return LIBUSB_ERROR_OTHER;
}
pOpenSCManagerA = (POPENSCMANAGERA)GetProcAddress(h, "OpenSCManagerA");
if (pOpenSCManagerA == NULL) {
usbi_warn(ctx, "failed to find %s in Advapi32\n", "OpenSCManagerA");
goto error_free_library;
}
pOpenServiceA = (POPENSERVICEA)GetProcAddress(h, "OpenServiceA");
if (pOpenServiceA == NULL) {
usbi_warn(ctx, "failed to find %s in Advapi32\n", "OpenServiceA");
goto error_free_library;
}
pCloseServiceHandle = (PCLOSESERVICEHANDLE)GetProcAddress(h, "CloseServiceHandle");
if (pCloseServiceHandle == NULL) {
usbi_warn(ctx, "failed to find %s in Advapi32\n", "CloseServiceHandle");
goto error_free_library;
}
managerHandle = pOpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
if (managerHandle == NULL) {
usbi_warn(ctx, "failed to open service control manager: %s", windows_error_str(0));
goto error_free_library;
}
serviceHandle = pOpenServiceA(managerHandle, "UsbDk", GENERIC_READ);
pCloseServiceHandle(managerHandle);
if (serviceHandle == NULL) {
if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
usbi_warn(ctx, "failed to open UsbDk service: %s", windows_error_str(0));
FreeLibrary(h);
return LIBUSB_ERROR_NOT_FOUND;
}
pCloseServiceHandle(serviceHandle);
FreeLibrary(h);
return load_usbdk_helper_dll(ctx);
error_free_library:
FreeLibrary(h);
return LIBUSB_ERROR_OTHER;
}
static void usbdk_exit(struct libusb_context *ctx)
{
UNUSED(ctx);
unload_usbdk_helper_dll();
}
static int usbdk_get_session_id_for_device(struct libusb_context *ctx,
PUSB_DK_DEVICE_ID id, unsigned long *session_id)
{
char dev_identity[ARRAYSIZE(id->DeviceID) + ARRAYSIZE(id->InstanceID) + 1];
if (snprintf(dev_identity, sizeof(dev_identity), "%S%S", id->DeviceID, id->InstanceID) == -1) {
usbi_warn(ctx, "cannot form device identity");
return LIBUSB_ERROR_NOT_SUPPORTED;
}
*session_id = htab_hash(dev_identity);
return LIBUSB_SUCCESS;
}
static void usbdk_release_config_descriptors(struct usbdk_device_priv *priv, uint8_t count)
{
uint8_t i;
for (i = 0; i < count; i++)
usbdk_helper.ReleaseConfigurationDescriptor(priv->config_descriptors[i]);
free(priv->config_descriptors);
priv->config_descriptors = NULL;
}
static int usbdk_cache_config_descriptors(struct libusb_context *ctx,
struct usbdk_device_priv *priv, PUSB_DK_DEVICE_INFO info)
{
uint8_t i;
USB_DK_CONFIG_DESCRIPTOR_REQUEST Request;
Request.ID = info->ID;
priv->config_descriptors = calloc(info->DeviceDescriptor.bNumConfigurations, sizeof(PUSB_CONFIGURATION_DESCRIPTOR));
if (priv->config_descriptors == NULL) {
usbi_err(ctx, "failed to allocate configuration descriptors holder");
return LIBUSB_ERROR_NO_MEM;
}
for (i = 0; i < info->DeviceDescriptor.bNumConfigurations; i++) {
ULONG Length;
Request.Index = i;
if (!usbdk_helper.GetConfigurationDescriptor(&Request, &priv->config_descriptors[i], &Length)) {
usbi_err(ctx, "failed to retrieve configuration descriptors");
usbdk_release_config_descriptors(priv, i);
return LIBUSB_ERROR_OTHER;
}
}
return LIBUSB_SUCCESS;
}
static inline int usbdk_device_priv_init(struct libusb_context *ctx, struct libusb_device *dev, PUSB_DK_DEVICE_INFO info)
{
struct usbdk_device_priv *priv = usbi_get_device_priv(dev);
priv->ID = info->ID;
priv->active_configuration = 0;
return usbdk_cache_config_descriptors(ctx, priv, info);
}
static void usbdk_device_init(struct libusb_device *dev, PUSB_DK_DEVICE_INFO info)
{
dev->bus_number = (uint8_t)info->FilterID;
dev->port_number = (uint8_t)info->Port;
dev->parent_dev = NULL;
// Addresses in libusb are 1-based
dev->device_address = (uint8_t)(info->Port + 1);
static_assert(sizeof(dev->device_descriptor) == sizeof(info->DeviceDescriptor),
"mismatch between libusb and OS device descriptor sizes");
memcpy(&dev->device_descriptor, &info->DeviceDescriptor, LIBUSB_DT_DEVICE_SIZE);
usbi_localize_device_descriptor(&dev->device_descriptor);
switch (info->Speed) {
case LowSpeed:
dev->speed = LIBUSB_SPEED_LOW;
break;
case FullSpeed:
dev->speed = LIBUSB_SPEED_FULL;
break;
case HighSpeed:
dev->speed = LIBUSB_SPEED_HIGH;
break;
case SuperSpeed:
dev->speed = LIBUSB_SPEED_SUPER;
break;
case NoSpeed:
default:
dev->speed = LIBUSB_SPEED_UNKNOWN;
break;
}
}
static int usbdk_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs)
{
int r = LIBUSB_SUCCESS;
ULONG i;
struct discovered_devs *discdevs = NULL;
ULONG dev_number;
PUSB_DK_DEVICE_INFO devices;
if (!usbdk_helper.GetDevicesList(&devices, &dev_number))
return LIBUSB_ERROR_OTHER;
for (i = 0; i < dev_number; i++) {
unsigned long session_id;
struct libusb_device *dev = NULL;
if (usbdk_get_session_id_for_device(ctx, &devices[i].ID, &session_id))
continue;
dev = usbi_get_device_by_session_id(ctx, session_id);
if (dev == NULL) {
dev = usbi_alloc_device(ctx, session_id);
if (dev == NULL) {
usbi_err(ctx, "failed to allocate a new device structure");
continue;
}
usbdk_device_init(dev, &devices[i]);
if (usbdk_device_priv_init(ctx, dev, &devices[i]) != LIBUSB_SUCCESS) {
libusb_unref_device(dev);
continue;
}
usbi_connect_device(dev);
}
if (_discdevs) {
discdevs = discovered_devs_append(*_discdevs, dev);
libusb_unref_device(dev);
if (!discdevs) {
usbi_err(ctx, "cannot append new device to list");
r = LIBUSB_ERROR_NO_MEM;
goto func_exit;
}
*_discdevs = discdevs;
}
}
func_exit:
usbdk_helper.ReleaseDevicesList(devices);
return r;
}
static int usbdk_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, void *buffer, size_t len)
{
struct usbdk_device_priv *priv = usbi_get_device_priv(dev);
PUSB_CONFIGURATION_DESCRIPTOR config_header;
size_t size;
config_header = (PUSB_CONFIGURATION_DESCRIPTOR)priv->config_descriptors[config_index];
size = min(config_header->wTotalLength, len);
memcpy(buffer, config_header, size);
return (int)size;
}
static int usbdk_get_config_descriptor_by_value(struct libusb_device *dev, uint8_t bConfigurationValue,
void **buffer)
{
struct usbdk_device_priv *priv = usbi_get_device_priv(dev);
PUSB_CONFIGURATION_DESCRIPTOR config_header;
uint8_t index;
for (index = 0; index < dev->device_descriptor.bNumConfigurations; index++) {
config_header = priv->config_descriptors[index];
if (config_header->bConfigurationValue == bConfigurationValue) {
*buffer = priv->config_descriptors[index];
return (int)config_header->wTotalLength;
}
}
return LIBUSB_ERROR_NOT_FOUND;
}
static int usbdk_get_active_config_descriptor(struct libusb_device *dev, void *buffer, size_t len)
{
struct usbdk_device_priv *priv = usbi_get_device_priv(dev);
return usbdk_get_config_descriptor(dev, priv->active_configuration, buffer, len);
}
static int usbdk_open(struct libusb_device_handle *dev_handle)
{
struct libusb_device *dev = dev_handle->dev;
struct libusb_context *ctx = DEVICE_CTX(dev);
struct windows_context_priv *priv = usbi_get_context_priv(ctx);
struct usbdk_device_priv *device_priv = usbi_get_device_priv(dev);
device_priv->redirector_handle = usbdk_helper.StartRedirect(&device_priv->ID);
if (device_priv->redirector_handle == INVALID_HANDLE_VALUE) {
usbi_err(ctx, "Redirector startup failed");
device_priv->redirector_handle = NULL;
return LIBUSB_ERROR_OTHER;
}
device_priv->system_handle = usbdk_helper.GetRedirectorSystemHandle(device_priv->redirector_handle);
if (CreateIoCompletionPort(device_priv->system_handle, priv->completion_port, (ULONG_PTR)dev_handle, 0) == NULL) {
usbi_err(ctx, "failed to associate handle to I/O completion port: %s", windows_error_str(0));
usbdk_helper.StopRedirect(device_priv->redirector_handle);
device_priv->system_handle = NULL;
device_priv->redirector_handle = NULL;
return LIBUSB_ERROR_OTHER;
}
return LIBUSB_SUCCESS;
}
static void usbdk_close(struct libusb_device_handle *dev_handle)
{
struct usbdk_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
if (!usbdk_helper.StopRedirect(priv->redirector_handle))
usbi_err(HANDLE_CTX(dev_handle), "Redirector shutdown failed");
priv->system_handle = NULL;
priv->redirector_handle = NULL;
}
static int usbdk_get_configuration(struct libusb_device_handle *dev_handle, uint8_t *config)
{
struct usbdk_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
*config = priv->active_configuration;
return LIBUSB_SUCCESS;
}
static int usbdk_set_configuration(struct libusb_device_handle *dev_handle, uint8_t config)
{
UNUSED(dev_handle);
UNUSED(config);
return LIBUSB_SUCCESS;
}
static int usbdk_claim_interface(struct libusb_device_handle *dev_handle, uint8_t iface)
{
UNUSED(dev_handle);
UNUSED(iface);
return LIBUSB_SUCCESS;
}
static int usbdk_set_interface_altsetting(struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting)
{
struct usbdk_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
if (!usbdk_helper.SetAltsetting(priv->redirector_handle, iface, altsetting)) {
usbi_err(HANDLE_CTX(dev_handle), "SetAltsetting failed: %s", windows_error_str(0));
return LIBUSB_ERROR_NO_DEVICE;
}
return LIBUSB_SUCCESS;
}
static int usbdk_release_interface(struct libusb_device_handle *dev_handle, uint8_t iface)
{
UNUSED(dev_handle);
UNUSED(iface);
return LIBUSB_SUCCESS;
}
static int usbdk_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
{
struct usbdk_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
if (!usbdk_helper.ResetPipe(priv->redirector_handle, endpoint)) {
usbi_err(HANDLE_CTX(dev_handle), "ResetPipe failed: %s", windows_error_str(0));
return LIBUSB_ERROR_NO_DEVICE;
}
return LIBUSB_SUCCESS;
}
static int usbdk_reset_device(struct libusb_device_handle *dev_handle)
{
struct usbdk_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
if (!usbdk_helper.ResetDevice(priv->redirector_handle)) {
usbi_err(HANDLE_CTX(dev_handle), "ResetDevice failed: %s", windows_error_str(0));
return LIBUSB_ERROR_NO_DEVICE;
}
return LIBUSB_SUCCESS;
}
static void usbdk_destroy_device(struct libusb_device *dev)
{
struct usbdk_device_priv *priv = usbi_get_device_priv(dev);
if (priv->config_descriptors != NULL)
usbdk_release_config_descriptors(priv, dev->device_descriptor.bNumConfigurations);
}
static void usbdk_clear_transfer_priv(struct usbi_transfer *itransfer)
{
struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer);
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
safe_free(transfer_priv->IsochronousPacketsArray);
safe_free(transfer_priv->IsochronousResultsArray);
}
}
static int usbdk_do_control_transfer(struct usbi_transfer *itransfer)
{
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct usbdk_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer);
OVERLAPPED *overlapped = get_transfer_priv_overlapped(itransfer);
TransferResult transResult;
transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
transfer_priv->request.BufferLength = transfer->length;
transfer_priv->request.TransferType = ControlTransferType;
set_transfer_priv_handle(itransfer, priv->system_handle);
if (transfer->buffer[0] & LIBUSB_ENDPOINT_IN)
transResult = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
else
transResult = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
switch (transResult) {
case TransferSuccess:
windows_force_sync_completion(itransfer, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
break;
case TransferSuccessAsync:
break;
case TransferFailure:
usbi_err(TRANSFER_CTX(transfer), "ControlTransfer failed: %s", windows_error_str(0));
return LIBUSB_ERROR_IO;
}
return LIBUSB_SUCCESS;
}
static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer)
{
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct usbdk_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer);
OVERLAPPED *overlapped = get_transfer_priv_overlapped(itransfer);
TransferResult transferRes;
transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
transfer_priv->request.BufferLength = transfer->length;
transfer_priv->request.EndpointAddress = transfer->endpoint;
switch (transfer->type) {
case LIBUSB_TRANSFER_TYPE_BULK:
transfer_priv->request.TransferType = BulkTransferType;
break;
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
transfer_priv->request.TransferType = InterruptTransferType;
break;
}
set_transfer_priv_handle(itransfer, priv->system_handle);
if (IS_XFERIN(transfer))
transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
else
transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
switch (transferRes) {
case TransferSuccess:
windows_force_sync_completion(itransfer, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
break;
case TransferSuccessAsync:
break;
case TransferFailure:
usbi_err(TRANSFER_CTX(transfer), "ReadPipe/WritePipe failed: %s", windows_error_str(0));
return LIBUSB_ERROR_IO;
}
return LIBUSB_SUCCESS;
}
static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer)
{
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct usbdk_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer);
OVERLAPPED *overlapped = get_transfer_priv_overlapped(itransfer);
TransferResult transferRes;
int i;
transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
transfer_priv->request.BufferLength = transfer->length;
transfer_priv->request.EndpointAddress = transfer->endpoint;
transfer_priv->request.TransferType = IsochronousTransferType;
transfer_priv->request.IsochronousPacketsArraySize = transfer->num_iso_packets;
transfer_priv->IsochronousPacketsArray = malloc(transfer->num_iso_packets * sizeof(ULONG64));
transfer_priv->request.IsochronousPacketsArray = (PVOID64)transfer_priv->IsochronousPacketsArray;
if (!transfer_priv->IsochronousPacketsArray) {
usbi_err(TRANSFER_CTX(transfer), "Allocation of IsochronousPacketsArray failed");
return LIBUSB_ERROR_NO_MEM;
}
transfer_priv->IsochronousResultsArray = malloc(transfer->num_iso_packets * sizeof(USB_DK_ISO_TRANSFER_RESULT));
transfer_priv->request.Result.IsochronousResultsArray = (PVOID64)transfer_priv->IsochronousResultsArray;
if (!transfer_priv->IsochronousResultsArray) {
usbi_err(TRANSFER_CTX(transfer), "Allocation of isochronousResultsArray failed");
return LIBUSB_ERROR_NO_MEM;
}
for (i = 0; i < transfer->num_iso_packets; i++)
transfer_priv->IsochronousPacketsArray[i] = transfer->iso_packet_desc[i].length;
set_transfer_priv_handle(itransfer, priv->system_handle);
if (IS_XFERIN(transfer))
transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
else
transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
switch (transferRes) {
case TransferSuccess:
windows_force_sync_completion(itransfer, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
break;
case TransferSuccessAsync:
break;
case TransferFailure:
return LIBUSB_ERROR_IO;
}
return LIBUSB_SUCCESS;
}
static int usbdk_submit_transfer(struct usbi_transfer *itransfer)
{
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
switch (transfer->type) {
case LIBUSB_TRANSFER_TYPE_CONTROL:
return usbdk_do_control_transfer(itransfer);
case LIBUSB_TRANSFER_TYPE_BULK:
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET))
return LIBUSB_ERROR_NOT_SUPPORTED; //TODO: Check whether we can support this in UsbDk
return usbdk_do_bulk_transfer(itransfer);
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
return usbdk_do_iso_transfer(itransfer);
default:
// Should not get here since windows_submit_transfer() validates
// the transfer->type field
usbi_err(TRANSFER_CTX(transfer), "unsupported endpoint type %d", transfer->type);
return LIBUSB_ERROR_NOT_SUPPORTED;
}
}
static enum libusb_transfer_status usbdk_copy_transfer_data(struct usbi_transfer *itransfer, DWORD length)
{
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer);
UNUSED(length);
if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
ULONG64 i;
for (i = 0; i < transfer_priv->request.IsochronousPacketsArraySize; i++) {
struct libusb_iso_packet_descriptor *lib_desc = &transfer->iso_packet_desc[i];
switch (transfer_priv->IsochronousResultsArray[i].TransferResult) {
case STATUS_SUCCESS:
case STATUS_CANCELLED:
case STATUS_REQUEST_CANCELED:
lib_desc->status = LIBUSB_TRANSFER_COMPLETED; // == ERROR_SUCCESS
break;
default:
lib_desc->status = LIBUSB_TRANSFER_ERROR; // ERROR_UNKNOWN_EXCEPTION;
break;
}
lib_desc->actual_length = (unsigned int)transfer_priv->IsochronousResultsArray[i].ActualLength;
}
}
itransfer->transferred += (int)transfer_priv->request.Result.GenResult.BytesTransferred;
return usbd_status_to_libusb_transfer_status((USBD_STATUS)transfer_priv->request.Result.GenResult.UsbdStatus);
}
const struct windows_backend usbdk_backend = {
usbdk_init,
usbdk_exit,
usbdk_get_device_list,
NULL, /* usbdk_get_device_string */
usbdk_open,
usbdk_close,
usbdk_get_active_config_descriptor,
usbdk_get_config_descriptor,
usbdk_get_config_descriptor_by_value,
usbdk_get_configuration,
usbdk_set_configuration,
usbdk_claim_interface,
usbdk_release_interface,
usbdk_set_interface_altsetting,
usbdk_clear_halt,
usbdk_reset_device,
usbdk_destroy_device,
usbdk_submit_transfer,
NULL, /* cancel_transfer */
usbdk_clear_transfer_priv,
usbdk_copy_transfer_data,
NULL, /* endpoint_supports_raw_io */
NULL, /* endpoint_set_raw_io */
NULL, /* get_max_raw_io_transfer_size */
};
@@ -0,0 +1,106 @@
/*
* windows UsbDk backend for libusb 1.0
* Copyright © 2014 Red Hat, Inc.
* Authors:
* Dmitry Fleytman <dmitry@daynix.com>
* Pavel Gurvich <pavel@daynix.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_WINDOWS_USBDK_H
#define LIBUSB_WINDOWS_USBDK_H
#include "windows_common.h"
typedef struct USB_DK_CONFIG_DESCRIPTOR_REQUEST {
USB_DK_DEVICE_ID ID;
ULONG64 Index;
} USB_DK_CONFIG_DESCRIPTOR_REQUEST, *PUSB_DK_CONFIG_DESCRIPTOR_REQUEST;
typedef enum {
TransferFailure = 0,
TransferSuccess,
TransferSuccessAsync
} TransferResult;
typedef enum {
NoSpeed = 0,
LowSpeed,
FullSpeed,
HighSpeed,
SuperSpeed
} USB_DK_DEVICE_SPEED;
typedef enum {
ControlTransferType,
BulkTransferType,
InterruptTransferType,
IsochronousTransferType
} USB_DK_TRANSFER_TYPE;
typedef BOOL (__cdecl *USBDK_GET_DEVICES_LIST)(
PUSB_DK_DEVICE_INFO *DeviceInfo,
PULONG DeviceNumber
);
typedef void (__cdecl *USBDK_RELEASE_DEVICES_LIST)(
PUSB_DK_DEVICE_INFO DeviceInfo
);
typedef HANDLE (__cdecl *USBDK_START_REDIRECT)(
PUSB_DK_DEVICE_ID DeviceId
);
typedef BOOL (__cdecl *USBDK_STOP_REDIRECT)(
HANDLE DeviceHandle
);
typedef BOOL (__cdecl *USBDK_GET_CONFIGURATION_DESCRIPTOR)(
PUSB_DK_CONFIG_DESCRIPTOR_REQUEST Request,
PUSB_CONFIGURATION_DESCRIPTOR *Descriptor,
PULONG Length
);
typedef void (__cdecl *USBDK_RELEASE_CONFIGURATION_DESCRIPTOR)(
PUSB_CONFIGURATION_DESCRIPTOR Descriptor
);
typedef TransferResult (__cdecl *USBDK_WRITE_PIPE)(
HANDLE DeviceHandle,
PUSB_DK_TRANSFER_REQUEST Request,
LPOVERLAPPED lpOverlapped
);
typedef TransferResult (__cdecl *USBDK_READ_PIPE)(
HANDLE DeviceHandle,
PUSB_DK_TRANSFER_REQUEST Request,
LPOVERLAPPED lpOverlapped
);
typedef BOOL (__cdecl *USBDK_ABORT_PIPE)(
HANDLE DeviceHandle,
ULONG64 PipeAddress
);
typedef BOOL (__cdecl *USBDK_RESET_PIPE)(
HANDLE DeviceHandle,
ULONG64 PipeAddress
);
typedef BOOL (__cdecl *USBDK_SET_ALTSETTING)(
HANDLE DeviceHandle,
ULONG64 InterfaceIdx,
ULONG64 AltSettingIdx
);
typedef BOOL (__cdecl *USBDK_RESET_DEVICE)(
HANDLE DeviceHandle
);
typedef HANDLE (__cdecl *USBDK_GET_REDIRECTOR_SYSTEM_HANDLE)(
HANDLE DeviceHandle
);
#endif
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,792 @@
/*
* Windows backend for libusb 1.0
* Copyright © 2009-2012 Pete Batard <pete@akeo.ie>
* With contributions from Michael Plante, Orin Eman et al.
* Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
* Major code testing contribution by Xiaofan Chen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef LIBUSB_WINDOWS_WINUSB_H
#define LIBUSB_WINDOWS_WINUSB_H
#include <devioctl.h>
#include <initguid.h>
#include <usbiodef.h>
#include "windows_common.h"
#define MAX_CTRL_BUFFER_LENGTH 4096
#define MAX_USB_STRING_LENGTH 128
#define MAX_HID_REPORT_SIZE 1024
#define MAX_HID_DESCRIPTOR_SIZE 256
#define MAX_GUID_STRING_LENGTH 39
#define MAX_PATH_LENGTH 256
#define MAX_KEY_LENGTH 256
#define LIST_SEPARATOR ';'
// Handle code for HID interface that have been claimed ("dibs")
#define INTERFACE_CLAIMED ((HANDLE)(intptr_t)0xD1B5)
// Additional return code for HID operations that completed synchronously
#define LIBUSB_COMPLETED (LIBUSB_SUCCESS + 1)
// libusb0 Filter Device Interface GUID
DEFINE_GUID(GUID_DEVINTERFACE_LIBUSB0_FILTER, 0xF9F3FF14, 0xAE21, 0x48A0, 0x8A, 0x25, 0x80, 0x11, 0xA7, 0xA9, 0x31, 0xD9);
// The following define MUST be == sizeof(USB_DESCRIPTOR_REQUEST)
#define USB_DESCRIPTOR_REQUEST_SIZE 12U
/*
* Multiple USB API backend support
*/
#define USB_API_UNSUPPORTED 0
#define USB_API_HUB 1
#define USB_API_COMPOSITE 2
#define USB_API_WINUSBX 3
#define USB_API_HID 4
#define USB_API_MAX 5
// Sub-APIs for WinUSB-like driver APIs (WinUSB, libusbK, libusb-win32 through the libusbK DLL)
// Must have the same values as the KUSB_DRVID enum from libusbk.h
#define SUB_API_NOTSET -1
#define SUB_API_LIBUSBK 0
#define SUB_API_LIBUSB0 1
#define SUB_API_WINUSB 2
#define SUB_API_MAX 3
struct windows_usb_api_backend {
const uint8_t id;
const char * const designation;
const char * const * const driver_name_list; // Driver name, without .sys, e.g. "usbccgp"
const uint8_t nb_driver_names;
bool (*init)(struct libusb_context *ctx);
void (*exit)(void);
int (*open)(int sub_api, struct libusb_device_handle *dev_handle);
void (*close)(int sub_api, struct libusb_device_handle *dev_handle);
int (*configure_endpoints)(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface);
int (*claim_interface)(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface);
int (*set_interface_altsetting)(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting);
int (*release_interface)(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface);
int (*clear_halt)(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint);
int (*reset_device)(int sub_api, struct libusb_device_handle *dev_handle);
int (*submit_bulk_transfer)(int sub_api, struct usbi_transfer *itransfer);
int (*submit_iso_transfer)(int sub_api, struct usbi_transfer *itransfer);
int (*submit_control_transfer)(int sub_api, struct usbi_transfer *itransfer);
int (*cancel_transfer)(int sub_api, struct usbi_transfer *itransfer);
enum libusb_transfer_status (*copy_transfer_data)(int sub_api, struct usbi_transfer *itransfer, DWORD length);
int (*endpoint_supports_raw_io)(int sub_api, struct libusb_device_handle *dev_handle, uint8_t endpoint);
int (*endpoint_set_raw_io)(int sub_api, struct libusb_device_handle *dev_handle, uint8_t endpoint, int enable);
int (*get_max_raw_io_transfer_size)(int sub_api, struct libusb_device_handle *dev_handle, uint8_t endpoint);
};
extern const struct windows_usb_api_backend usb_api_backend[USB_API_MAX];
#define PRINT_UNSUPPORTED_API(fname) \
usbi_dbg(NULL, "unsupported API call for '%s' " \
"(unrecognized device driver)", #fname)
#define CHECK_SUPPORTED_API(apip, fname) \
do { \
if ((apip)->fname == NULL) { \
PRINT_UNSUPPORTED_API(fname); \
return LIBUSB_ERROR_NOT_SUPPORTED; \
} \
} while (0)
/*
* private structures definition
* with inline pseudo constructors/destructors
*/
// TODO (v2+): move hid desc to libusb.h?
struct libusb_hid_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdHID;
uint8_t bCountryCode;
uint8_t bNumDescriptors;
uint8_t bClassDescriptorType;
uint16_t wClassDescriptorLength;
};
#define LIBUSB_DT_HID_SIZE 9
#define HID_MAX_CONFIG_DESC_SIZE (LIBUSB_DT_CONFIG_SIZE + LIBUSB_DT_INTERFACE_SIZE \
+ LIBUSB_DT_HID_SIZE + 2 * LIBUSB_DT_ENDPOINT_SIZE)
#define HID_MAX_REPORT_SIZE 1024
#define HID_IN_EP 0x81
#define HID_OUT_EP 0x02
#define LIBUSB_REQ_RECIPIENT(request_type) ((request_type) & 0x1F)
#define LIBUSB_REQ_TYPE(request_type) ((request_type) & (0x03 << 5))
#define LIBUSB_REQ_IN(request_type) ((request_type) & LIBUSB_ENDPOINT_IN)
#define LIBUSB_REQ_OUT(request_type) (!LIBUSB_REQ_IN(request_type))
// The following are used for HID reports IOCTLs
#define HID_IN_CTL_CODE(id) \
CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#define HID_OUT_CTL_CODE(id) \
CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
#define IOCTL_HID_GET_FEATURE HID_OUT_CTL_CODE(100)
#define IOCTL_HID_GET_INPUT_REPORT HID_OUT_CTL_CODE(104)
#define IOCTL_HID_SET_FEATURE HID_IN_CTL_CODE(100)
#define IOCTL_HID_SET_OUTPUT_REPORT HID_IN_CTL_CODE(101)
enum libusb_hid_request_type {
HID_REQ_GET_REPORT = 0x01,
HID_REQ_GET_IDLE = 0x02,
HID_REQ_GET_PROTOCOL = 0x03,
HID_REQ_SET_REPORT = 0x09,
HID_REQ_SET_IDLE = 0x0A,
HID_REQ_SET_PROTOCOL = 0x0B
};
enum libusb_hid_report_type {
HID_REPORT_TYPE_INPUT = 0x01,
HID_REPORT_TYPE_OUTPUT = 0x02,
HID_REPORT_TYPE_FEATURE = 0x03
};
struct hid_device_priv {
uint16_t vid;
uint16_t pid;
uint8_t config;
uint8_t nb_interfaces;
bool uses_report_ids[3]; // input, ouptput, feature
uint16_t input_report_size;
uint16_t output_report_size;
uint16_t feature_report_size;
uint16_t usage;
uint16_t usagePage;
WCHAR string[3][MAX_USB_STRING_LENGTH];
uint8_t string_index[3]; // man, prod, ser
};
static inline struct winusb_device_priv *winusb_device_priv_init(struct libusb_device *dev)
{
struct winusb_device_priv *priv = usbi_get_device_priv(dev);
int i;
usbi_mutex_init(&priv->interface_lock);
priv->apib = &usb_api_backend[USB_API_UNSUPPORTED];
priv->sub_api = SUB_API_NOTSET;
for (i = 0; i < USB_MAXINTERFACES; i++) {
priv->usb_interface[i].apib = &usb_api_backend[USB_API_UNSUPPORTED];
priv->usb_interface[i].sub_api = SUB_API_NOTSET;
}
return priv;
}
static inline void winusb_device_priv_release(struct libusb_device *dev)
{
struct winusb_device_priv *priv = usbi_get_device_priv(dev);
int i;
free(priv->dev_id);
free(priv->path);
if ((dev->device_descriptor.bNumConfigurations > 0) && (priv->config_descriptor != NULL)) {
for (i = 0; i < dev->device_descriptor.bNumConfigurations; i++) {
if (priv->config_descriptor[i] == NULL)
continue;
free((UCHAR *)priv->config_descriptor[i] - USB_DESCRIPTOR_REQUEST_SIZE);
}
}
free(priv->config_descriptor);
free(priv->hid);
for (i = 0; i < USB_MAXINTERFACES; i++) {
free(priv->usb_interface[i].path);
free(priv->usb_interface[i].endpoint);
}
usbi_mutex_destroy(&priv->interface_lock);
}
// used to match a device driver (including filter drivers) against a supported API
struct driver_lookup {
char list[MAX_KEY_LENGTH + 1]; // REG_MULTI_SZ list of services (driver) names
const DWORD reg_prop; // SPDRP registry key to use to retrieve list
const char *designation; // internal designation (for debug output)
};
/*
* Windows DDK API definitions. Most of it copied from MinGW's includes
*/
typedef DWORD DEVNODE, DEVINST;
typedef DEVNODE *PDEVNODE, *PDEVINST;
typedef DWORD RETURN_TYPE;
typedef RETURN_TYPE CONFIGRET;
#define CR_SUCCESS 0x00000000
/* Cfgmgr32 dependencies */
DLL_DECLARE_HANDLE(Cfgmgr32);
DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Parent, (PDEVINST, DEVINST, ULONG));
DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Child, (PDEVINST, DEVINST, ULONG));
/* AdvAPI32 dependencies */
DLL_DECLARE_HANDLE(AdvAPI32);
DLL_DECLARE_FUNC_PREFIXED(WINAPI, LONG, p, RegQueryValueExA, (HKEY, LPCSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, LONG, p, RegCloseKey, (HKEY));
/* SetupAPI dependencies */
DLL_DECLARE_HANDLE(SetupAPI);
DLL_DECLARE_FUNC_PREFIXED(WINAPI, HDEVINFO, p, SetupDiGetClassDevsA, (LPCGUID, PCSTR, HWND, DWORD));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInfo, (HDEVINFO, DWORD, PSP_DEVINFO_DATA));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInterfaces, (HDEVINFO, PSP_DEVINFO_DATA,
LPCGUID, DWORD, PSP_DEVICE_INTERFACE_DATA));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceInstanceIdA, (HDEVINFO, PSP_DEVINFO_DATA,
PCSTR, DWORD, PDWORD));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceInterfaceDetailA, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA,
PSP_DEVICE_INTERFACE_DETAIL_DATA_A, DWORD, PDWORD, PSP_DEVINFO_DATA));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceRegistryPropertyA, (HDEVINFO,
PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiDestroyDeviceInfoList, (HDEVINFO));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDevRegKey, (HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDeviceInterfaceRegKey, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA, DWORD, DWORD));
#define FILE_DEVICE_USB FILE_DEVICE_UNKNOWN
#define USB_GET_NODE_INFORMATION 258
#define USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION 260
#define USB_GET_NODE_CONNECTION_INFORMATION_EX 274
#define USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 279
#define USB_CTL_CODE(id) \
CTL_CODE(FILE_DEVICE_USB, (id), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_USB_GET_NODE_INFORMATION \
USB_CTL_CODE(USB_GET_NODE_INFORMATION)
#define IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION \
USB_CTL_CODE(USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION)
#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX \
USB_CTL_CODE(USB_GET_NODE_CONNECTION_INFORMATION_EX)
#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 \
USB_CTL_CODE(USB_GET_NODE_CONNECTION_INFORMATION_EX_V2)
typedef enum _USB_CONNECTION_STATUS {
NoDeviceConnected,
DeviceConnected,
DeviceFailedEnumeration,
DeviceGeneralFailure,
DeviceCausedOvercurrent,
DeviceNotEnoughPower,
DeviceNotEnoughBandwidth,
DeviceHubNestedTooDeeply,
DeviceInLegacyHub,
DeviceEnumerating,
DeviceReset
} USB_CONNECTION_STATUS;
typedef enum _USB_DEVICE_SPEED {
UsbLowSpeed = 0,
UsbFullSpeed,
UsbHighSpeed,
UsbSuperSpeed,
UsbSuperSpeedPlus // Not in Microsoft headers
} USB_DEVICE_SPEED;
typedef enum _USB_HUB_NODE {
UsbHub,
UsbMIParent
} USB_HUB_NODE;
#if defined(_MSC_VER)
// disable /W4 MSVC warnings that are benign
#pragma warning(push)
#pragma warning(disable:4214) // bit field types other than int
#endif
// Most of the structures below need to be packed
#pragma pack(push, 1)
typedef struct _USB_HUB_DESCRIPTOR {
UCHAR bDescriptorLength;
UCHAR bDescriptorType;
UCHAR bNumberOfPorts;
USHORT wHubCharacteristics;
UCHAR bPowerOnToPowerGood;
UCHAR bHubControlCurrent;
UCHAR bRemoveAndPowerMask[64];
} USB_HUB_DESCRIPTOR, *PUSB_HUB_DESCRIPTOR;
typedef struct _USB_HUB_INFORMATION {
USB_HUB_DESCRIPTOR HubDescriptor;
BOOLEAN HubIsBusPowered;
} USB_HUB_INFORMATION, *PUSB_HUB_INFORMATION;
typedef struct _USB_NODE_INFORMATION {
USB_HUB_NODE NodeType;
union {
USB_HUB_INFORMATION HubInformation;
// USB_MI_PARENT_INFORMATION MiParentInformation;
} u;
} USB_NODE_INFORMATION, *PUSB_NODE_INFORMATION;
typedef struct _USB_DESCRIPTOR_REQUEST {
ULONG ConnectionIndex;
struct {
UCHAR bmRequest;
UCHAR bRequest;
USHORT wValue;
USHORT wIndex;
USHORT wLength;
} SetupPacket;
// UCHAR Data[0];
} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST;
typedef struct _USB_CONFIGURATION_DESCRIPTOR_SHORT {
USB_DESCRIPTOR_REQUEST req;
USB_CONFIGURATION_DESCRIPTOR desc;
} USB_CONFIGURATION_DESCRIPTOR_SHORT;
typedef struct USB_INTERFACE_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
UCHAR bInterfaceNumber;
UCHAR bAlternateSetting;
UCHAR bNumEndpoints;
UCHAR bInterfaceClass;
UCHAR bInterfaceSubClass;
UCHAR bInterfaceProtocol;
UCHAR iInterface;
} USB_INTERFACE_DESCRIPTOR, *PUSB_INTERFACE_DESCRIPTOR;
typedef struct _USB_NODE_CONNECTION_INFORMATION_EX {
ULONG ConnectionIndex;
USB_DEVICE_DESCRIPTOR DeviceDescriptor;
UCHAR CurrentConfigurationValue;
UCHAR Speed;
BOOLEAN DeviceIsHub;
USHORT DeviceAddress;
ULONG NumberOfOpenPipes;
USB_CONNECTION_STATUS ConnectionStatus;
// USB_PIPE_INFO PipeList[0];
} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX;
typedef union _USB_PROTOCOLS {
ULONG ul;
struct {
ULONG Usb110:1;
ULONG Usb200:1;
ULONG Usb300:1;
ULONG ReservedMBZ:29;
};
} USB_PROTOCOLS, *PUSB_PROTOCOLS;
typedef union _USB_NODE_CONNECTION_INFORMATION_EX_V2_FLAGS {
ULONG ul;
struct {
ULONG DeviceIsOperatingAtSuperSpeedOrHigher:1;
ULONG DeviceIsSuperSpeedCapableOrHigher:1;
ULONG DeviceIsOperatingAtSuperSpeedPlusOrHigher:1;
ULONG DeviceIsSuperSpeedPlusCapableOrHigher:1;
ULONG ReservedMBZ:28;
};
} USB_NODE_CONNECTION_INFORMATION_EX_V2_FLAGS, *PUSB_NODE_CONNECTION_INFORMATION_EX_V2_FLAGS;
typedef struct _USB_NODE_CONNECTION_INFORMATION_EX_V2 {
ULONG ConnectionIndex;
ULONG Length;
USB_PROTOCOLS SupportedUsbProtocols;
USB_NODE_CONNECTION_INFORMATION_EX_V2_FLAGS Flags;
} USB_NODE_CONNECTION_INFORMATION_EX_V2, *PUSB_NODE_CONNECTION_INFORMATION_EX_V2;
#pragma pack(pop)
#if defined(_MSC_VER)
// Restore original warnings
#pragma warning(pop)
#endif
/* winusb.dll interface */
/* pipe policies */
#define SHORT_PACKET_TERMINATE 0x01
#define AUTO_CLEAR_STALL 0x02
#define PIPE_TRANSFER_TIMEOUT 0x03
#define IGNORE_SHORT_PACKETS 0x04
#define ALLOW_PARTIAL_READS 0x05
#define AUTO_FLUSH 0x06
#define RAW_IO 0x07
#define MAXIMUM_TRANSFER_SIZE 0x08
/* libusbK */
#define ISO_ALWAYS_START_ASAP 0x21
typedef struct _USBD_ISO_PACKET_DESCRIPTOR {
ULONG Offset;
ULONG Length;
USBD_STATUS Status;
} USBD_ISO_PACKET_DESCRIPTOR, *PUSBD_ISO_PACKET_DESCRIPTOR;
typedef enum _USBD_PIPE_TYPE {
UsbdPipeTypeControl,
UsbdPipeTypeIsochronous,
UsbdPipeTypeBulk,
UsbdPipeTypeInterrupt
} USBD_PIPE_TYPE;
typedef struct {
USBD_PIPE_TYPE PipeType;
UCHAR PipeId;
USHORT MaximumPacketSize;
UCHAR Interval;
ULONG MaximumBytesPerInterval;
} WINUSB_PIPE_INFORMATION_EX, *PWINUSB_PIPE_INFORMATION_EX;
#pragma pack(push, 1)
typedef struct _WINUSB_SETUP_PACKET {
UCHAR RequestType;
UCHAR Request;
USHORT Value;
USHORT Index;
USHORT Length;
} WINUSB_SETUP_PACKET, *PWINUSB_SETUP_PACKET;
#pragma pack(pop)
typedef PVOID WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE;
typedef PVOID WINUSB_ISOCH_BUFFER_HANDLE, *PWINUSB_ISOCH_BUFFER_HANDLE;
typedef BOOL (WINAPI *WinUsb_AbortPipe_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID
);
typedef BOOL (WINAPI *WinUsb_ControlTransfer_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
WINUSB_SETUP_PACKET SetupPacket,
PUCHAR Buffer,
ULONG BufferLength,
PULONG LengthTransferred,
LPOVERLAPPED Overlapped
);
typedef BOOL (WINAPI *WinUsb_FlushPipe_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID
);
typedef BOOL (WINAPI *WinUsb_Free_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle
);
typedef BOOL (WINAPI *WinUsb_GetAssociatedInterface_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR AssociatedInterfaceIndex,
PWINUSB_INTERFACE_HANDLE AssociatedInterfaceHandle
);
typedef BOOL (WINAPI *WinUsb_Initialize_t)(
HANDLE DeviceHandle,
PWINUSB_INTERFACE_HANDLE InterfaceHandle
);
typedef BOOL (WINAPI *WinUsb_QueryPipeEx_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR AlternateInterfaceHandle,
UCHAR PipeIndex,
PWINUSB_PIPE_INFORMATION_EX PipeInformationEx
);
typedef BOOL (WINAPI *WinUsb_ReadIsochPipeAsap_t)(
PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle,
ULONG Offset,
ULONG Length,
BOOL ContinueStream,
ULONG NumberOfPackets,
PUSBD_ISO_PACKET_DESCRIPTOR IsoPacketDescriptors,
LPOVERLAPPED Overlapped
);
typedef BOOL (WINAPI *WinUsb_ReadPipe_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID,
PUCHAR Buffer,
ULONG BufferLength,
PULONG LengthTransferred,
LPOVERLAPPED Overlapped
);
typedef BOOL (WINAPI *WinUsb_RegisterIsochBuffer_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID,
PVOID Buffer,
ULONG BufferLength,
PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle
);
typedef BOOL (WINAPI *WinUsb_ResetPipe_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID
);
typedef BOOL (WINAPI *WinUsb_SetCurrentAlternateSetting_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR AlternateSetting
);
typedef BOOL (WINAPI *WinUsb_SetPipePolicy_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID,
ULONG PolicyType,
ULONG ValueLength,
PVOID Value
);
typedef BOOL (WINAPI *WinUsb_GetPipePolicy_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID,
ULONG PolicyType,
PULONG ValueLength,
PVOID Value
);
typedef BOOL (WINAPI *WinUsb_UnregisterIsochBuffer_t)(
WINUSB_ISOCH_BUFFER_HANDLE BufferHandle
);
typedef BOOL (WINAPI *WinUsb_WriteIsochPipeAsap_t)(
WINUSB_ISOCH_BUFFER_HANDLE BufferHandle,
ULONG Offset,
ULONG Length,
BOOL ContinueStream,
LPOVERLAPPED Overlapped
);
typedef BOOL (WINAPI *WinUsb_WritePipe_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID,
PUCHAR Buffer,
ULONG BufferLength,
PULONG LengthTransferred,
LPOVERLAPPED Overlapped
);
/* /!\ These must match the ones from the official libusbk.h */
typedef enum _KUSB_FNID {
KUSB_FNID_Init,
KUSB_FNID_Free,
KUSB_FNID_ClaimInterface,
KUSB_FNID_ReleaseInterface,
KUSB_FNID_SetAltInterface,
KUSB_FNID_GetAltInterface,
KUSB_FNID_GetDescriptor,
KUSB_FNID_ControlTransfer,
KUSB_FNID_SetPowerPolicy,
KUSB_FNID_GetPowerPolicy,
KUSB_FNID_SetConfiguration,
KUSB_FNID_GetConfiguration,
KUSB_FNID_ResetDevice,
KUSB_FNID_Initialize,
KUSB_FNID_SelectInterface,
KUSB_FNID_GetAssociatedInterface,
KUSB_FNID_Clone,
KUSB_FNID_QueryInterfaceSettings,
KUSB_FNID_QueryDeviceInformation,
KUSB_FNID_SetCurrentAlternateSetting,
KUSB_FNID_GetCurrentAlternateSetting,
KUSB_FNID_QueryPipe,
KUSB_FNID_SetPipePolicy,
KUSB_FNID_GetPipePolicy,
KUSB_FNID_ReadPipe,
KUSB_FNID_WritePipe,
KUSB_FNID_ResetPipe,
KUSB_FNID_AbortPipe,
KUSB_FNID_FlushPipe,
KUSB_FNID_IsoReadPipe,
KUSB_FNID_IsoWritePipe,
KUSB_FNID_GetCurrentFrameNumber,
KUSB_FNID_GetOverlappedResult,
KUSB_FNID_GetProperty,
KUSB_FNID_COUNT,
} KUSB_FNID;
typedef struct _KLIB_VERSION {
INT Major;
INT Minor;
INT Micro;
INT Nano;
} KLIB_VERSION, *PKLIB_VERSION;
typedef BOOL (WINAPI *LibK_GetProcAddress_t)(
PVOID ProcAddress,
INT DriverID,
INT FunctionID
);
typedef VOID (WINAPI *LibK_GetVersion_t)(
PKLIB_VERSION Version
);
typedef BOOL (WINAPI *LibK_ResetDevice_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle
);
//KISO_PACKET is equivalent of libusb_iso_packet_descriptor except uses absolute "offset" field instead of sequential Lengths
typedef struct _KISO_PACKET {
UINT offset;
USHORT actual_length; //changed from libusbk_shared.h "Length" for clarity
USHORT status;
} KISO_PACKET, *PKISO_PACKET;
typedef enum _KISO_FLAG {
KISO_FLAG_NONE = 0,
KISO_FLAG_SET_START_FRAME = 0x00000001,
} KISO_FLAG;
//KISO_CONTEXT is the conceptual equivalent of libusb_transfer except is isochronous-specific and must match libusbk's version
typedef struct _KISO_CONTEXT {
KISO_FLAG Flags;
UINT StartFrame;
SHORT ErrorCount;
SHORT NumberOfPackets;
UINT UrbHdrStatus;
KISO_PACKET IsoPackets[0];
} KISO_CONTEXT, *PKISO_CONTEXT;
typedef BOOL(WINAPI *LibK_IsoReadPipe_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID,
PUCHAR Buffer,
ULONG BufferLength,
LPOVERLAPPED Overlapped,
PKISO_CONTEXT IsoContext
);
typedef BOOL(WINAPI *LibK_IsoWritePipe_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID,
PUCHAR Buffer,
ULONG BufferLength,
LPOVERLAPPED Overlapped,
PKISO_CONTEXT IsoContext
);
struct winusb_interface {
HMODULE hDll;
WinUsb_AbortPipe_t AbortPipe;
WinUsb_ControlTransfer_t ControlTransfer;
WinUsb_FlushPipe_t FlushPipe;
WinUsb_Free_t Free;
WinUsb_GetAssociatedInterface_t GetAssociatedInterface;
WinUsb_Initialize_t Initialize;
WinUsb_ReadPipe_t ReadPipe;
WinUsb_ResetPipe_t ResetPipe;
WinUsb_SetCurrentAlternateSetting_t SetCurrentAlternateSetting;
WinUsb_SetPipePolicy_t SetPipePolicy;
WinUsb_GetPipePolicy_t GetPipePolicy;
WinUsb_WritePipe_t WritePipe;
union {
struct {
// Isochoronous functions for libusbK sub api:
LibK_IsoReadPipe_t IsoReadPipe;
LibK_IsoWritePipe_t IsoWritePipe;
// Reset device function for libusbK sub api:
LibK_ResetDevice_t ResetDevice;
};
struct {
// Isochronous functions for WinUSB sub api:
WinUsb_QueryPipeEx_t QueryPipeEx;
WinUsb_ReadIsochPipeAsap_t ReadIsochPipeAsap;
WinUsb_RegisterIsochBuffer_t RegisterIsochBuffer;
WinUsb_UnregisterIsochBuffer_t UnregisterIsochBuffer;
WinUsb_WriteIsochPipeAsap_t WriteIsochPipeAsap;
};
};
};
/* hid.dll interface */
#define HIDP_STATUS_SUCCESS 0x110000
typedef void * PHIDP_PREPARSED_DATA;
#pragma pack(push, 1)
typedef struct _HIDD_ATTIRBUTES {
ULONG Size;
USHORT VendorID;
USHORT ProductID;
USHORT VersionNumber;
} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
#pragma pack(pop)
typedef USHORT USAGE;
typedef struct _HIDP_CAPS {
USAGE Usage;
USAGE UsagePage;
USHORT InputReportByteLength;
USHORT OutputReportByteLength;
USHORT FeatureReportByteLength;
USHORT Reserved[17];
USHORT NumberLinkCollectionNodes;
USHORT NumberInputButtonCaps;
USHORT NumberInputValueCaps;
USHORT NumberInputDataIndices;
USHORT NumberOutputButtonCaps;
USHORT NumberOutputValueCaps;
USHORT NumberOutputDataIndices;
USHORT NumberFeatureButtonCaps;
USHORT NumberFeatureValueCaps;
USHORT NumberFeatureDataIndices;
} HIDP_CAPS, *PHIDP_CAPS;
typedef enum _HIDP_REPORT_TYPE {
HidP_Input,
HidP_Output,
HidP_Feature
} HIDP_REPORT_TYPE;
typedef struct _HIDP_VALUE_CAPS {
USAGE UsagePage;
UCHAR ReportID;
BOOLEAN IsAlias;
USHORT BitField;
USHORT LinkCollection;
USAGE LinkUsage;
USAGE LinkUsagePage;
BOOLEAN IsRange;
BOOLEAN IsStringRange;
BOOLEAN IsDesignatorRange;
BOOLEAN IsAbsolute;
BOOLEAN HasNull;
UCHAR Reserved;
USHORT BitSize;
USHORT ReportCount;
USHORT Reserved2[5];
ULONG UnitsExp;
ULONG Units;
LONG LogicalMin, LogicalMax;
LONG PhysicalMin, PhysicalMax;
union {
struct {
USAGE UsageMin, UsageMax;
USHORT StringMin, StringMax;
USHORT DesignatorMin, DesignatorMax;
USHORT DataIndexMin, DataIndexMax;
} Range;
struct {
USAGE Usage, Reserved1;
USHORT StringIndex, Reserved2;
USHORT DesignatorIndex, Reserved3;
USHORT DataIndex, Reserved4;
} NotRange;
} u;
} HIDP_VALUE_CAPS, *PHIDP_VALUE_CAPS;
DLL_DECLARE_HANDLE(hid);
DLL_DECLARE_FUNC(WINAPI, VOID, HidD_GetHidGuid, (LPGUID));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetAttributes, (HANDLE, PHIDD_ATTRIBUTES));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetPreparsedData, (HANDLE, PHIDP_PREPARSED_DATA *));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_FreePreparsedData, (PHIDP_PREPARSED_DATA));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetManufacturerString, (HANDLE, PVOID, ULONG));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetProductString, (HANDLE, PVOID, ULONG));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetSerialNumberString, (HANDLE, PVOID, ULONG));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetIndexedString, (HANDLE, ULONG, PVOID, ULONG));
DLL_DECLARE_FUNC(WINAPI, LONG, HidP_GetCaps, (PHIDP_PREPARSED_DATA, PHIDP_CAPS));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_SetNumInputBuffers, (HANDLE, ULONG));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetPhysicalDescriptor, (HANDLE, PVOID, ULONG));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_FlushQueue, (HANDLE));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidP_GetValueCaps, (HIDP_REPORT_TYPE, PHIDP_VALUE_CAPS, PULONG, PHIDP_PREPARSED_DATA));
#endif
@@ -0,0 +1,223 @@
/*
* libusb strerror code
* Copyright © 2013 Hans de Goede <hdegoede@redhat.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 <ctype.h>
#include <string.h>
/** \ingroup libusb_misc
* How to add a new \ref libusb_strerror() translation:
* <ol>
* <li> Download the latest \c strerror.c from:<br>
* https://raw.github.com/libusb/libusb/master/libusb/strerror.c </li>
* <li> Open the file in an UTF-8 capable editor </li>
* <li> Add the 2 letter <a href="https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes">ISO 639-1</a>
* code for your locale at the end of \c usbi_locale_supported[]<br>
* Eg. for Chinese, you would add "zh" so that:
* \code... usbi_locale_supported[] = { "en", "nl", "fr" };\endcode
* becomes:
* \code... usbi_locale_supported[] = { "en", "nl", "fr", "zh" };\endcode </li>
* <li> Copy the <tt>{ / * English (en) * / ... }</tt> section and add it at the end of \c usbi_localized_errors<br>
* Eg. for Chinese, the last section of \c usbi_localized_errors could look like:
* \code
* }, { / * Chinese (zh) * /
* "Success",
* ...
* "Other error",
* },
* };\endcode </li>
* <li> Translate each of the English messages from the section you copied into your language </li>
* <li> Save the file (in UTF-8 format) and send it to \c libusb-devel\@lists.sourceforge.net </li>
* </ol>
*/
static const char * const usbi_locale_supported[] = { "en", "nl", "fr", "ru", "de", "hu" };
static const char * const usbi_localized_errors[ARRAYSIZE(usbi_locale_supported)][LIBUSB_ERROR_COUNT] = {
{ /* English (en) */
"Success",
"Input/Output Error",
"Invalid parameter",
"Access denied (insufficient permissions)",
"No such device (it may have been disconnected)",
"Entity not found",
"Resource busy",
"Operation timed out",
"Overflow",
"Pipe error",
"System call interrupted (perhaps due to signal)",
"Insufficient memory",
"Operation not supported or unimplemented on this platform",
"Other error",
}, { /* Dutch (nl) */
"Gelukt",
"Invoer-/uitvoerfout",
"Ongeldig argument",
"Toegang geweigerd (onvoldoende toegangsrechten)",
"Apparaat bestaat niet (verbinding met apparaat verbroken?)",
"Niet gevonden",
"Apparaat of hulpbron is bezig",
"Bewerking verlopen",
"Waarde is te groot",
"Gebroken pijp",
"Onderbroken systeemaanroep",
"Onvoldoende geheugen beschikbaar",
"Bewerking wordt niet ondersteund",
"Andere fout",
}, { /* French (fr) */
"Succès",
"Erreur d'entrée/sortie",
"Paramètre invalide",
"Accès refusé (permissions insuffisantes)",
"Périphérique introuvable (peut-être déconnecté)",
"Elément introuvable",
"Resource déjà occupée",
"Operation expirée",
"Débordement",
"Erreur de pipe",
"Appel système abandonné (peut-être à cause d’un signal)",
"Mémoire insuffisante",
"Opération non supportée or non implémentée sur cette plateforme",
"Autre erreur",
}, { /* Russian (ru) */
"Успех",
"Ошибка ввода/вывода",
"Неверный параметр",
"Доступ запрещён (не хватает прав)",
"Устройство отсутствует (возможно, оно было отсоединено)",
"Элемент не найден",
"Ресурс занят",
"Истекло время ожидания операции",
"Переполнение",
"Ошибка канала",
"Системный вызов прерван (возможно, сигналом)",
"Память исчерпана",
"Операция не поддерживается данной платформой",
"Неизвестная ошибка"
}, { /* German (de) */
"Erfolgreich",
"Eingabe-/Ausgabefehler",
"Ungültiger Parameter",
"Keine Berechtigung (Zugriffsrechte fehlen)",
"Kein passendes Gerät gefunden (es könnte entfernt worden sein)",
"Entität nicht gefunden",
"Die Ressource ist belegt",
"Die Wartezeit für die Operation ist abgelaufen",
"Mehr Daten empfangen als erwartet",
"Datenübergabe unterbrochen (broken pipe)",
"Unterbrechung während des Betriebssystemaufrufs",
"Nicht genügend Hauptspeicher verfügbar",
"Die Operation wird nicht unterstützt oder ist auf dieser Platform nicht implementiert",
"Allgemeiner Fehler",
}, { /* Hungarian (hu) */
"Sikeres",
"Be-/kimeneti hiba",
"Érvénytelen paraméter",
"Hozzáférés megtagadva",
"Az eszköz nem található (eltávolították?)",
"Nem található",
"Az erőforrás foglalt",
"Időtúllépés",
"Túlcsordulás",
"Törött adatcsatorna",
"Rendszerhívás megszakítva",
"Nincs elég memória",
"A művelet nem támogatott ezen a rendszeren",
"Általános hiba",
},
};
static const char * const (*usbi_error_strings)[LIBUSB_ERROR_COUNT] = &usbi_localized_errors[0];
/** \ingroup libusb_misc
* Set the language, and only the language, not the encoding! used for
* translatable libusb messages.
*
* This takes a locale string in the default setlocale format: lang[-region]
* or lang[_country_region][.codeset]. Only the lang part of the string is
* used, and only 2 letter ISO 639-1 codes are accepted for it, such as "de".
* The optional region, country_region or codeset parts are ignored. This
* means that functions which return translatable strings will NOT honor the
* specified encoding.
* All strings returned are encoded as UTF-8 strings.
*
* If libusb_setlocale() is not called, all messages will be in English.
*
* The following functions return translatable strings: libusb_strerror().
* Note that the libusb log messages controlled through LIBUSB_OPTION_LOG_LEVEL
* are not translated, they are always in English.
*
* For POSIX UTF-8 environments if you want libusb to follow the standard
* locale settings, call libusb_setlocale(setlocale(LC_MESSAGES, NULL)),
* after your app has done its locale setup.
*
* \param locale locale-string in the form of lang[_country_region][.codeset]
* or lang[-region], where lang is a 2 letter ISO 639-1 code
* \returns \ref LIBUSB_SUCCESS on success
* \returns \ref LIBUSB_ERROR_INVALID_PARAM if the locale doesn't meet the requirements
* \returns \ref LIBUSB_ERROR_NOT_FOUND if the requested language is not supported
* \returns a LIBUSB_ERROR code on other errors
*/
int API_EXPORTED libusb_setlocale(const char *locale)
{
size_t i;
if (!locale || strlen(locale) < 2
|| (locale[2] != '\0' && locale[2] != '-' && locale[2] != '_' && locale[2] != '.'))
return LIBUSB_ERROR_INVALID_PARAM;
for (i = 0; i < ARRAYSIZE(usbi_locale_supported); i++) {
if (usbi_locale_supported[i][0] == tolower((unsigned char)locale[0])
&& usbi_locale_supported[i][1] == tolower((unsigned char)locale[1]))
break;
}
if (i == ARRAYSIZE(usbi_locale_supported))
return LIBUSB_ERROR_NOT_FOUND;
usbi_error_strings = &usbi_localized_errors[i];
return LIBUSB_SUCCESS;
}
/** \ingroup libusb_misc
* Returns a constant string with a short description of the given error code,
* this description is intended for displaying to the end user and will be in
* the language set by libusb_setlocale().
*
* The returned string is encoded in UTF-8.
*
* The messages always start with a capital letter and end without any dot.
* The caller must not free() the returned string.
*
* \param errcode the error code whose description is desired
* \returns a short description of the error code in UTF-8 encoding
*/
DEFAULT_VISIBILITY const char * LIBUSB_CALL libusb_strerror(int errcode)
{
int errcode_index = -errcode;
if (errcode_index < 0 || errcode_index >= LIBUSB_ERROR_COUNT) {
/* "Other Error", which should always be our last message, is returned */
errcode_index = LIBUSB_ERROR_COUNT - 1;
}
return (*usbi_error_strings)[errcode_index];
}
@@ -0,0 +1,342 @@
/* -*- Mode: C; indent-tabs-mode:t ; c-basic-offset:8 -*- */
/*
* Synchronous I/O functions for libusb
* Copyright © 2007-2008 Daniel Drake <dsd@gentoo.org>
* Copyright © 2019 Nathan Hjelm <hjelmn@cs.unm.edu>
* Copyright © 2019 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
*/
#include "libusbi.h"
#include <assert.h>
#include <string.h>
/**
* @defgroup libusb_syncio Synchronous device I/O
*
* This page documents libusb's synchronous (blocking) API for USB device I/O.
* This interface is easy to use but has some limitations. More advanced users
* may wish to consider using the \ref libusb_asyncio "asynchronous I/O API" instead.
*/
static void LIBUSB_CALL sync_transfer_cb(struct libusb_transfer *transfer)
{
usbi_dbg(TRANSFER_CTX(transfer), "actual_length=%d", transfer->actual_length);
int *completed = transfer->user_data;
*completed = 1;
/*
* Right after setting 'completed', another thread might free the transfer, so don't
* access it beyond this point. The instantiating thread (not necessarily the
* current one) interprets the result and frees the transfer.
*/
}
static void sync_transfer_wait_for_completion(struct libusb_transfer *transfer)
{
int r, *completed = transfer->user_data;
struct libusb_context *ctx = HANDLE_CTX(transfer->dev_handle);
while (!*completed) {
r = libusb_handle_events_completed(ctx, completed);
if (r < 0) {
if (r == LIBUSB_ERROR_INTERRUPTED)
continue;
usbi_err(ctx, "libusb_handle_events failed: %s, cancelling transfer and retrying",
libusb_error_name(r));
libusb_cancel_transfer(transfer);
continue;
}
if (NULL == transfer->dev_handle) {
/* transfer completion after libusb_close() */
transfer->status = LIBUSB_TRANSFER_NO_DEVICE;
*completed = 1;
}
}
}
/** \ingroup libusb_syncio
* Perform a USB control transfer.
*
* The direction of the transfer is inferred from the bmRequestType field of
* the setup packet.
*
* The wValue, wIndex and wLength fields values should be given in host-endian
* byte order.
*
* \param dev_handle a handle for the device to communicate with
* \param bmRequestType the request type field for the setup packet
* \param bRequest the request field for the setup packet
* \param wValue the value field for the setup packet
* \param wIndex the index field for the setup packet
* \param data a suitably-sized data buffer for either input or output
* (depending on direction bits within bmRequestType)
* \param wLength the length field for the setup packet. The data buffer should
* be at least this size.
* \param timeout timeout (in milliseconds) that this function should wait
* before giving up due to no response being received. For an unlimited
* timeout, use value 0.
* \returns on success, the number of bytes actually transferred
* \returns \ref LIBUSB_ERROR_TIMEOUT if the transfer timed out
* \returns \ref LIBUSB_ERROR_PIPE if the control request was not supported by the
* device
* \returns \ref LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
* \returns \ref LIBUSB_ERROR_BUSY if called from event handling context
* \returns \ref LIBUSB_ERROR_INVALID_PARAM if the transfer size is larger than
* the operating system and/or hardware can support (see \ref asynclimits)
* \returns another LIBUSB_ERROR code on other failures
*/
int API_EXPORTED libusb_control_transfer(libusb_device_handle *dev_handle,
uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
unsigned char *data, uint16_t wLength, unsigned int timeout)
{
struct libusb_transfer *transfer;
unsigned char *buffer;
int completed = 0;
int r;
if (usbi_handling_events(HANDLE_CTX(dev_handle)))
return LIBUSB_ERROR_BUSY;
transfer = libusb_alloc_transfer(0);
if (!transfer)
return LIBUSB_ERROR_NO_MEM;
buffer = malloc(LIBUSB_CONTROL_SETUP_SIZE + wLength);
if (!buffer) {
libusb_free_transfer(transfer);
return LIBUSB_ERROR_NO_MEM;
}
libusb_fill_control_setup(buffer, bmRequestType, bRequest, wValue, wIndex,
wLength);
if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT)
memcpy(buffer + LIBUSB_CONTROL_SETUP_SIZE, data, wLength);
libusb_fill_control_transfer(transfer, dev_handle, buffer,
sync_transfer_cb, &completed, timeout);
transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER;
r = libusb_submit_transfer(transfer);
if (r < 0) {
libusb_free_transfer(transfer);
return r;
}
sync_transfer_wait_for_completion(transfer);
if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN)
memcpy(data, libusb_control_transfer_get_data(transfer),
(size_t)transfer->actual_length);
switch (transfer->status) {
case LIBUSB_TRANSFER_COMPLETED:
r = transfer->actual_length;
break;
case LIBUSB_TRANSFER_TIMED_OUT:
r = LIBUSB_ERROR_TIMEOUT;
break;
case LIBUSB_TRANSFER_STALL:
r = LIBUSB_ERROR_PIPE;
break;
case LIBUSB_TRANSFER_NO_DEVICE:
r = LIBUSB_ERROR_NO_DEVICE;
break;
case LIBUSB_TRANSFER_OVERFLOW:
r = LIBUSB_ERROR_OVERFLOW;
break;
case LIBUSB_TRANSFER_ERROR:
case LIBUSB_TRANSFER_CANCELLED:
r = LIBUSB_ERROR_IO;
break;
default:
usbi_warn(HANDLE_CTX(dev_handle),
"unrecognised status code %d", transfer->status);
r = LIBUSB_ERROR_OTHER;
}
libusb_free_transfer(transfer);
return r;
}
static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle,
unsigned char endpoint, unsigned char *buffer, int length,
int *transferred, unsigned int timeout, unsigned char type)
{
struct libusb_transfer *transfer;
int completed = 0;
int r;
if (usbi_handling_events(HANDLE_CTX(dev_handle)))
return LIBUSB_ERROR_BUSY;
transfer = libusb_alloc_transfer(0);
if (!transfer)
return LIBUSB_ERROR_NO_MEM;
libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer, length,
sync_transfer_cb, &completed, timeout);
transfer->type = type;
r = libusb_submit_transfer(transfer);
if (r < 0) {
libusb_free_transfer(transfer);
return r;
}
sync_transfer_wait_for_completion(transfer);
if (transferred) {
assert(transfer->actual_length >= 0);
*transferred = transfer->actual_length;
}
switch (transfer->status) {
case LIBUSB_TRANSFER_COMPLETED:
r = 0;
break;
case LIBUSB_TRANSFER_TIMED_OUT:
r = LIBUSB_ERROR_TIMEOUT;
break;
case LIBUSB_TRANSFER_STALL:
r = LIBUSB_ERROR_PIPE;
break;
case LIBUSB_TRANSFER_OVERFLOW:
r = LIBUSB_ERROR_OVERFLOW;
break;
case LIBUSB_TRANSFER_NO_DEVICE:
r = LIBUSB_ERROR_NO_DEVICE;
break;
case LIBUSB_TRANSFER_ERROR:
case LIBUSB_TRANSFER_CANCELLED:
r = LIBUSB_ERROR_IO;
break;
default:
usbi_warn(HANDLE_CTX(dev_handle),
"unrecognised status code %d", transfer->status);
r = LIBUSB_ERROR_OTHER;
}
libusb_free_transfer(transfer);
return r;
}
/** \ingroup libusb_syncio
* Perform a USB bulk transfer. The direction of the transfer is inferred from
* the direction bits of the endpoint address.
*
* For bulk reads, the <tt>length</tt> field indicates the maximum length of
* data you are expecting to receive. If less data arrives than expected,
* this function will return that data, so be sure to check the
* <tt>transferred</tt> output parameter.
*
* You should also check the <tt>transferred</tt> parameter for bulk writes.
* Not all of the data may have been written.
*
* Also check <tt>transferred</tt> when dealing with a timeout error code.
* libusb may have to split your transfer into a number of chunks to satisfy
* underlying O/S requirements, meaning that the timeout may expire after
* the first few chunks have completed. libusb is careful not to lose any data
* that may have been transferred; do not assume that timeout conditions
* indicate a complete lack of I/O. See \ref asynctimeout for more details.
*
* \param dev_handle a handle for the device to communicate with
* \param endpoint the address of a valid endpoint to communicate with
* \param data a suitably-sized data buffer for either input or output
* (depending on endpoint)
* \param length for bulk writes, the number of bytes from data to be sent. for
* bulk reads, the maximum number of bytes to receive into the data buffer.
* \param transferred output location for the number of bytes actually
* transferred. Since version 1.0.21 (\ref LIBUSB_API_VERSION >= 0x01000105),
* it is legal to pass a NULL pointer if you do not wish to receive this
* information.
* \param timeout timeout (in milliseconds) that this function should wait
* before giving up due to no response being received. For an unlimited
* timeout, use value 0.
*
* \returns 0 on success (and populates <tt>transferred</tt>)
* \returns \ref LIBUSB_ERROR_TIMEOUT if the transfer timed out (and populates
* <tt>transferred</tt>)
* \returns \ref LIBUSB_ERROR_PIPE if the endpoint halted
* \returns \ref LIBUSB_ERROR_OVERFLOW if the device offered more data, see
* \ref libusb_packetoverflow
* \returns \ref LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
* \returns \ref LIBUSB_ERROR_BUSY if called from event handling context
* \returns \ref LIBUSB_ERROR_INVALID_PARAM if the transfer size is larger than
* the operating system and/or hardware can support (see \ref asynclimits)
* \returns another LIBUSB_ERROR code on other failures
*/
int API_EXPORTED libusb_bulk_transfer(libusb_device_handle *dev_handle,
unsigned char endpoint, unsigned char *data, int length,
int *transferred, unsigned int timeout)
{
return do_sync_bulk_transfer(dev_handle, endpoint, data, length,
transferred, timeout, LIBUSB_TRANSFER_TYPE_BULK);
}
/** \ingroup libusb_syncio
* Perform a USB interrupt transfer. The direction of the transfer is inferred
* from the direction bits of the endpoint address.
*
* For interrupt reads, the <tt>length</tt> field indicates the maximum length
* of data you are expecting to receive. If less data arrives than expected,
* this function will return that data, so be sure to check the
* <tt>transferred</tt> output parameter.
*
* You should also check the <tt>transferred</tt> parameter for interrupt
* writes. Not all of the data may have been written.
*
* Also check <tt>transferred</tt> when dealing with a timeout error code.
* libusb may have to split your transfer into a number of chunks to satisfy
* underlying O/S requirements, meaning that the timeout may expire after
* the first few chunks have completed. libusb is careful not to lose any data
* that may have been transferred; do not assume that timeout conditions
* indicate a complete lack of I/O. See \ref asynctimeout for more details.
*
* The default endpoint bInterval value is used as the polling interval.
*
* \param dev_handle a handle for the device to communicate with
* \param endpoint the address of a valid endpoint to communicate with
* \param data a suitably-sized data buffer for either input or output
* (depending on endpoint)
* \param length for bulk writes, the number of bytes from data to be sent. for
* bulk reads, the maximum number of bytes to receive into the data buffer.
* \param transferred output location for the number of bytes actually
* transferred. Will never be negative. Since version 1.0.21
* (\ref LIBUSB_API_VERSION >= 0x01000105), it is legal to pass a NULL
* pointer if you do not wish to receive this information.
* \param timeout timeout (in milliseconds) that this function should wait
* before giving up due to no response being received. For an unlimited
* timeout, use value 0.
*
* \returns 0 on success (and populates <tt>transferred</tt>)
* \returns \ref LIBUSB_ERROR_TIMEOUT if the transfer timed out
* \returns \ref LIBUSB_ERROR_PIPE if the endpoint halted
* \returns \ref LIBUSB_ERROR_OVERFLOW if the device offered more data, see
* \ref libusb_packetoverflow
* \returns \ref LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
* \returns \ref LIBUSB_ERROR_BUSY if called from event handling context
* \returns \ref LIBUSB_ERROR_INVALID_PARAM if the transfer size is larger than
* the operating system and/or hardware can support (see \ref asynclimits)
* \returns another LIBUSB_ERROR code on other error
*/
int API_EXPORTED libusb_interrupt_transfer(libusb_device_handle *dev_handle,
unsigned char endpoint, unsigned char *data, int length,
int *transferred, unsigned int timeout)
{
return do_sync_bulk_transfer(dev_handle, endpoint, data, length,
transferred, timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT);
}
@@ -0,0 +1,18 @@
/* This file is parsed by m4 and windres and RC.EXE so please keep it simple. */
#include "version_nano.h"
#ifndef LIBUSB_MAJOR
#define LIBUSB_MAJOR 1
#endif
#ifndef LIBUSB_MINOR
#define LIBUSB_MINOR 0
#endif
#ifndef LIBUSB_MICRO
#define LIBUSB_MICRO 30
#endif
#ifndef LIBUSB_NANO
#define LIBUSB_NANO 0
#endif
/* LIBUSB_RC is the release candidate suffix. Should normally be empty. */
#ifndef LIBUSB_RC
#define LIBUSB_RC ""
#endif
@@ -0,0 +1 @@
#define LIBUSB_NANO 12037
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<LibusbRootDir>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..'))\</LibusbRootDir>
<IntDir>$(LibusbRootDir)build\$(PlatformToolset)\$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
<OutDir>$(IntDir)..\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup>
<!--ClCompile Base-->
<ClCompile>
<AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_WIN32_WINNT=_WIN32_WINNT_VISTA;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<IntrinsicFunctions>true</IntrinsicFunctions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<!--Treat sources as utf-8-->
<AdditionalOptions Condition="'$(LibusbPlatformToolsetVersion)'&gt;'120'">/utf-8 %(AdditionalOptions)</AdditionalOptions>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<DiagnosticsFormat>Caret</DiagnosticsFormat>
</ClCompile>
<!--ClCompile Debug*-->
<ClCompile Condition="$(Configuration.StartsWith('Debug'))">
<Optimization>Disabled</Optimization>
</ClCompile>
<ClCompile Condition="$(Configuration.StartsWith('Debug')) And '$(EnableASAN)'=='true'">
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
</ClCompile>
<!--ClCompile Release*-->
<ClCompile Condition="$(Configuration.StartsWith('Release'))">
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<StringPooling>true</StringPooling>
<AdditionalOptions>/Gw %(AdditionalOptions)</AdditionalOptions>
<WholeProgramOptimization>true</WholeProgramOptimization>
</ClCompile>
<!--Link Base-->
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
</Link>
<!--Link Release*-->
<Link Condition="$(Configuration.StartsWith('Release'))">
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<AdditionalDependencies>kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<!--Link Base:Application-->
<Link Condition="'$(ConfigurationType)'=='Application'">
<SubSystem>Console</SubSystem>
</Link>
<Lib>
<TreatLibWarningAsErrors>true</TreatLibWarningAsErrors>
<LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>
</Lib>
</ItemDefinitionGroup>
</Project>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="Configuration.Base.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
</PropertyGroup>
</Project>
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Configuration">
<!--Will be overridden by value from command line, if provided-->
<PlatformToolset Condition="$(VisualStudioVersion)=='12.0'">v120</PlatformToolset>
<PlatformToolset Condition="$(VisualStudioVersion)=='14.0'">v140</PlatformToolset>
<PlatformToolset Condition="$(VisualStudioVersion)=='15.0'">v141</PlatformToolset>
<PlatformToolset Condition="$(VisualStudioVersion)=='16.0'">v142</PlatformToolset>
<PlatformToolset Condition="$(VisualStudioVersion)=='17.0'">v143</PlatformToolset>
<PlatformToolset Condition="$(VisualStudioVersion)=='18.0'">v145</PlatformToolset>
<!--We may need the equivalent of PlatformToolsetVersion before it's ready, so create it ourself-->
<LibusbPlatformToolsetVersion>$(PlatformToolset.Substring(1))</LibusbPlatformToolsetVersion>
<CharacterSet>Unicode</CharacterSet>
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
<!-- To use ASAN, just uncomment this. For simplicity, you should run VS/windbg/etc
(including the built executables themselves) after using vcvarsall or similar to setup
environment, as ASAN needs access to libs and executables in the toolchain paths.
-->
<!--<EnableASAN>true</EnableASAN>-->
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile Condition="$(Configuration.StartsWith('Debug'))">
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<ClCompile Condition="$(Configuration.StartsWith('Release'))">
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
</ItemDefinitionGroup>
<PropertyGroup Label="Globals" Condition="'$(LibusbPlatformToolsetVersion)'&lt;'142'">
<!--
WindowsSDKDesktopARMSupport and WindowsSDKDesktopARM64Support are
required to enable downlevel Windows SDKs to build "desktop" arm/arm64
binaries.
-->
<WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport>
<WindowsSDKDesktopARM64Support>true</WindowsSDKDesktopARM64Support>
<!--
WindowsTargetPlatformVersion must be set to explicit value for older
PlatformToolsets. Fetch it from environment variable.
vs2017/arm64 needs to be special cased to select 10.x SDK instead of 8.x
-->
<WindowsTargetPlatformVersion Condition="'$(LibusbPlatformToolsetVersion)'=='141' And $(Platform)=='ARM64'">10.0.19041.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion Condition="'$(LibusbPlatformToolsetVersion)'!='141' Or $(Platform)!='ARM64'">$(WindowsSDKVersion)</WindowsTargetPlatformVersion>
</PropertyGroup>
<PropertyGroup Label="Globals" Condition="'$(LibusbPlatformToolsetVersion)'&gt;='142'">
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
</Project>
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="Configuration.Base.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile Condition="'$(Configuration)'=='Debug'">
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
</ClCompile>
<ClCompile Condition="'$(Configuration)'=='Debug-Hotplug'">
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
</ClCompile>
<ClCompile Condition="'$(Configuration)'=='Debug-MT'">
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<ClCompile Condition="'$(Configuration)'=='Debug-Hotplug-MT'">
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<ClCompile Condition="'$(Configuration)'=='Release'">
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
</ClCompile>
<ClCompile Condition="'$(Configuration)'=='Release-Hotplug'">
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
</ClCompile>
<ClCompile Condition="'$(Configuration)'=='Release-MT'">
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<ClCompile Condition="'$(Configuration)'=='Release-Hotplug-MT'">
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
</ItemDefinitionGroup>
</Project>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="Configuration.Base.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
</PropertyGroup>
</Project>
@@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="ShowHotplugState" BeforeTargets="ClCompile">
<Message Condition="'$(EnableWindowsHotplug)' == 'true'" Text="EnableWindowsHotplug is enabled" Importance="High" />
<Message Condition="'$(EnableWindowsHotplug)' != 'true'" Text="EnableWindowsHotplug is disabled" Importance="High" />
</Target>
<ItemDefinitionGroup Condition="'$(EnableWindowsHotplug)' == 'true'">
<ClCompile>
<PreprocessorDefinitions>LIBUSB_WINDOWS_HOTPLUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug-MT|ARM64">
<Configuration>Debug-MT</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug-MT|Win32">
<Configuration>Debug-MT</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug-MT|x64">
<Configuration>Debug-MT</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release-MT|ARM64">
<Configuration>Release-MT</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release-MT|Win32">
<Configuration>Release-MT</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release-MT|x64">
<Configuration>Release-MT</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug-Hotplug|ARM64">
<Configuration>Debug-Hotplug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug-Hotplug|Win32">
<Configuration>Debug-Hotplug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug-Hotplug|x64">
<Configuration>Debug-Hotplug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release-Hotplug|ARM64">
<Configuration>Release-Hotplug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release-Hotplug|Win32">
<Configuration>Release-Hotplug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release-Hotplug|x64">
<Configuration>Release-Hotplug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug-Hotplug-MT|ARM64">
<Configuration>Debug-Hotplug-MT</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug-Hotplug-MT|Win32">
<Configuration>Debug-Hotplug-MT</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug-Hotplug-MT|x64">
<Configuration>Debug-Hotplug-MT</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release-Hotplug-MT|ARM64">
<Configuration>Release-Hotplug-MT</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release-Hotplug-MT|Win32">
<Configuration>Release-Hotplug-MT</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release-Hotplug-MT|x64">
<Configuration>Release-Hotplug-MT</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug-Hotplug'">
<EnableWindowsHotplug>true</EnableWindowsHotplug>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug-Hotplug-MT'">
<EnableWindowsHotplug>true</EnableWindowsHotplug>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release-Hotplug'">
<EnableWindowsHotplug>true</EnableWindowsHotplug>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release-Hotplug-MT'">
<EnableWindowsHotplug>true</EnableWindowsHotplug>
</PropertyGroup>
</Project>
@@ -0,0 +1,17 @@
$toolsets = "v120", "v140", "v141", "v142", "v143", "v145"
$platforms = "Win32", "x64", "ARM", "ARM64"
$configurations = "Debug", "Release"
foreach ($toolset in $toolsets) {
foreach ($plat in $platforms) {
if (("v120", "v140").contains($toolset) -and $plat -eq "ARM64") {
# VS2013,VS2015 don't support arm64
write-host ">>> PlatformToolset=$toolset,Platform=$plat SKIP"
continue
}
foreach ($conf in $configurations) {
write-host ">>> PlatformToolset=$toolset,Platform=$plat,Configuration=$conf"
msbuild -m -v:m -p:PlatformToolset=$toolset,Platform=$plat,Configuration=$conf $PSScriptRoot\libusb.sln
}
}
}
@@ -0,0 +1,62 @@
/* config.h. Manual config for MSVC. */
#ifndef _MSC_VER
#warn "msvc/config.h shouldn't be included for your development environment."
#error "Please make sure the msvc/ directory is removed from your build path."
#endif
/* Visual Studio 2013 or later is required */
#if (_MSC_VER < 1800)
#error "Visual Studio 2013 or later is required."
#endif
/* Visual Studio 2013 and 2015 do not support __func__ */
#if (_MSC_VER <= 1900)
#define __func__ __FUNCTION__
#endif
/* Visual Studio 2015 and later defines timespec */
#if (_MSC_VER >= 1900)
#define _TIMESPEC_DEFINED 1
#endif
/* Disable: warning C4127: conditional expression is constant */
#pragma warning(disable:4127)
/* Disable: warning C4200: nonstandard extension used : zero-sized array in struct/union */
#pragma warning(disable:4200)
/* Disable: warning C4201: nonstandard extension used : nameless struct/union */
#pragma warning(disable:4201)
/* Disable: warning C4324: structure was padded due to __declspec(align()) */
#pragma warning(disable:4324)
/* Disable: warning C4996: 'GetVersionExA': was declared deprecated */
#pragma warning(disable:4996)
#if (_MSC_VER > 1800)
/* Disable: warning C5287: operands are different enum types, supported after Visual Studio 2013 */
#pragma warning(disable:5287)
#endif
#if defined(_PREFAST_)
/* Disable "Banned API" errors when using the MS's WDK OACR/Prefast */
#pragma warning(disable:28719)
/* Disable "The function 'InitializeCriticalSection' must be called from within a try/except block" */
#pragma warning(disable:28125)
#endif
/* Define to the attribute for default visibility. */
#define DEFAULT_VISIBILITY /**/
/* 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 compiling for a Windows platform. */
#define PLATFORM_WINDOWS 1
/* Define to the attribute for enabling parameter checks on printf-like
functions. */
#define PRINTF_FORMAT(a, b) /**/
/* Define to 1 to output logging messages to the systemwide log. */
/* #undef USE_SYSTEM_LOGGING_FACILITY */
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="ProjectConfigurations.Base.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{8c7814a1-fd6e-4185-9ea0-8208119756d4}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="Configuration.Application.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="Base.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemGroup>
<ClCompile Include="..\examples\dpfp.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include=".\config.h" />
<ClInclude Include="..\libusb\libusb.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include=".\libusb_static.vcxproj">
<Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="ProjectConfigurations.Base.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{8c7814a2-fd6e-4185-9ea0-8208119756d4}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="Configuration.Application.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="Base.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>DPFP_THREADED;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\examples\dpfp.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include=".\config.h" />
<ClInclude Include="..\libusb\libusb.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include=".\libusb_static.vcxproj">
<Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="ProjectConfigurations.Base.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="Configuration.Application.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="Base.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>.\getopt;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__GNU_LIBRARY__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\examples\ezusb.c" />
<ClCompile Include="..\examples\fxload.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include=".\config.h" />
<ClInclude Include=".\getopt\getopt.h" />
<ClInclude Include="..\examples\ezusb.h" />
<ClInclude Include="..\libusb\libusb.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include=".\getopt.vcxproj">
<Project>{ae83e1b4-ce06-47ee-b7a3-c3a1d7c2d71e}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include=".\libusb_static.vcxproj">
<Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="ProjectConfigurations.Base.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="Configuration.StaticLibrary.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="Base.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>.\getopt;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_GL_UNUSED=;HAVE_STRING_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4100;4131;4702;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include=".\getopt\getopt.c" />
<ClCompile Include=".\getopt\getopt1.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include=".\getopt\bits\getopt_core.h" />
<ClInclude Include=".\getopt\bits\getopt_ext.h" />
<ClInclude Include=".\getopt\features.h" />
<ClInclude Include=".\getopt\gettext.h" />
<ClInclude Include=".\getopt\getopt.h" />
<ClInclude Include=".\getopt\getopt_int.h" />
<ClInclude Include=".\getopt\unistd.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,96 @@
/* Declarations for getopt (basic, portable features only).
Copyright (C) 1989-2026 Free Software Foundation, Inc.
This file is part of the GNU C Library and is also part of gnulib.
Patches to this file should be submitted to both projects.
The GNU C 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.
The GNU C 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 the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#ifndef _GETOPT_CORE_H
#define _GETOPT_CORE_H 1
/* This header should not be used directly; include getopt.h or
unistd.h instead. Unlike most bits headers, it does not have
a protective #error, because the guard macro for getopt.h in
gnulib is not fixed. */
__BEGIN_DECLS
/* For communication from 'getopt' to the caller.
When 'getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when 'ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
extern char *optarg;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to 'getopt'.
On entry to 'getopt', zero means this is the first call; initialize.
When 'getopt' returns -1, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, 'optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
extern int optind;
/* Callers store zero here to inhibit the error message 'getopt' prints
for unrecognized options. */
extern int opterr;
/* Set to an option character which was unrecognized. */
extern int optopt;
/* Get definitions and prototypes for functions to process the
arguments in ARGV (ARGC of them, minus the program name) for
options given in OPTS.
Return the option character from OPTS just read. Return -1 when
there are no more options. For unrecognized options, or options
missing arguments, 'optopt' is set to the option letter, and '?' is
returned.
The OPTS string is a list of characters which are recognized option
letters, optionally followed by colons, specifying that that letter
takes an argument, to be placed in 'optarg'.
If a letter in OPTS is followed by two colons, its argument is
optional. This behavior is specific to the GNU 'getopt'.
The argument '--' causes premature termination of argument
scanning, explicitly telling 'getopt' that there are no more
options.
If OPTS begins with '-', then non-option arguments are treated as
arguments to the option '\1'. This behavior is specific to the GNU
'getopt'. If OPTS begins with '+', or POSIXLY_CORRECT is set in
the environment, then do not permute arguments.
For standards compliance, the 'argv' argument has the type
char *const *, but this is inaccurate; if argument permutation is
enabled, the argv array (not the strings it points to) must be
writable. */
extern int getopt (int ___argc, char *const *___argv, const char *__shortopts)
__THROW __nonnull ((2, 3));
__END_DECLS
#endif /* getopt_core.h */
@@ -0,0 +1,77 @@
/* Declarations for getopt (GNU extensions).
Copyright (C) 1989-2026 Free Software Foundation, Inc.
This file is part of the GNU C Library and is also part of gnulib.
Patches to this file should be submitted to both projects.
The GNU C 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.
The GNU C 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 the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#ifndef _GETOPT_EXT_H
#define _GETOPT_EXT_H 1
/* This header should not be used directly; include getopt.h instead.
Unlike most bits headers, it does not have a protective #error,
because the guard macro for getopt.h in gnulib is not fixed. */
__BEGIN_DECLS
/* Describe the long-named options requested by the application.
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
of 'struct option' terminated by an element containing a name which is
zero.
The field 'has_arg' is:
no_argument (or 0) if the option does not take an argument,
required_argument (or 1) if the option requires an argument,
optional_argument (or 2) if the option takes an optional argument.
If the field 'flag' is not NULL, it points to a variable that is set
to the value given in the field 'val' when the option is found, but
left unchanged if the option is not found.
To have a long-named option do something other than set an 'int' to
a compiled-in constant, such as set a value from 'optarg', set the
option's 'flag' field to zero and its 'val' field to a nonzero
value (the equivalent single-letter option character, if there is
one). For long options that have a zero 'flag' field, 'getopt'
returns the contents of the 'val' field. */
struct option
{
const char *name;
/* has_arg can't be an enum because some compilers complain about
type mismatches in all the code that assumes it is an int. */
int has_arg;
int *flag;
int val;
};
/* Names for the values of the 'has_arg' field of 'struct option'. */
#define no_argument 0
#define required_argument 1
#define optional_argument 2
extern int getopt_long (int ___argc, char *__getopt_argv_const *___argv,
const char *__shortopts,
const struct option *__longopts, int *__longind)
__THROW __nonnull ((2, 3));
extern int getopt_long_only (int ___argc, char *__getopt_argv_const *___argv,
const char *__shortopts,
const struct option *__longopts, int *__longind)
__THROW __nonnull ((2, 3));
__END_DECLS
#endif /* getopt_ext.h */
@@ -0,0 +1,21 @@
/* Minimal features.h shim for standalone getopt build on MSVC. */
#ifndef _FEATURES_H
#define _FEATURES_H 1
#ifdef __cplusplus
# define __BEGIN_DECLS extern "C" {
# define __END_DECLS }
#else
# define __BEGIN_DECLS
# define __END_DECLS
#endif
#ifndef __THROW
# define __THROW
#endif
#ifndef __nonnull
# define __nonnull(params)
#endif
#endif /* _FEATURES_H */
@@ -0,0 +1,811 @@
/* Getopt for GNU.
Copyright (C) 1987-2026 Free Software Foundation, Inc.
This file is part of the GNU C Library and is also part of gnulib.
Patches to this file should be submitted to both projects.
The GNU C 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.
The GNU C 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 the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#ifndef _LIBC
# include <config.h>
#endif
#include "getopt.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifdef _LIBC
/* When used as part of glibc, error printing must be done differently
for standards compliance. getopt is not a cancellation point, so
it must not call functions that are, and it is specified by an
older standard than stdio locking, so it must not refer to
functions in the "user namespace" related to stdio locking.
Finally, it must use glibc's internal message translation so that
the messages are looked up in the proper text domain. */
# include <libintl.h>
# define fprintf __fxprintf_nocancel
# define flockfile(fp) _IO_flockfile (fp)
# define funlockfile(fp) _IO_funlockfile (fp)
#else
# include "gettext.h"
# define _(msgid) gettext (msgid)
/* When used standalone, flockfile and funlockfile might not be
available. */
# if (!defined _POSIX_THREAD_SAFE_FUNCTIONS \
|| (defined _WIN32 && ! defined __CYGWIN__))
# define flockfile(fp) /* nop */
# define funlockfile(fp) /* nop */
# endif
/* When used standalone, do not attempt to use alloca. */
# define __libc_use_alloca(size) 0
# undef alloca
# define alloca(size) (abort (), (void *)0)
#endif
/* This implementation of 'getopt' has three modes for handling
options interspersed with non-option arguments. It can stop
scanning for options at the first non-option argument encountered,
as POSIX specifies. It can continue scanning for options after the
first non-option argument, but permute 'argv' as it goes so that,
after 'getopt' is done, all the options precede all the non-option
arguments and 'optind' points to the first non-option argument.
Or, it can report non-option arguments as if they were arguments to
the option character '\x01'.
The default behavior of 'getopt_long' is to permute the argument list.
When this implementation is used standalone, the default behavior of
'getopt' is to stop at the first non-option argument, but when it is
used as part of GNU libc it also permutes the argument list. In both
cases, setting the environment variable POSIXLY_CORRECT to any value
disables permutation.
If the first character of the OPTSTRING argument to 'getopt' or
'getopt_long' is '+', both functions will stop at the first
non-option argument. If it is '-', both functions will report
non-option arguments as arguments to the option character '\x01'. */
#include "getopt_int.h"
/* For communication from 'getopt' to the caller.
When 'getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when 'ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
char *optarg;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to 'getopt'.
On entry to 'getopt', zero means this is the first call; initialize.
When 'getopt' returns -1, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, 'optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
/* 1003.2 says this must be 1 before any call. */
int optind = 1;
/* Callers store zero here to inhibit the error message
for unrecognized options. */
int opterr = 1;
/* Set to an option character which was unrecognized.
This must be initialized on some systems to avoid linking in the
system's own getopt implementation. */
int optopt = '?';
/* Keep a global copy of all internal members of getopt_data. */
static struct _getopt_data getopt_data;
/* Exchange two adjacent subsequences of ARGV.
One subsequence is elements [first_nonopt,last_nonopt)
which contains all the non-options that have been skipped so far.
The other is elements [last_nonopt,optind), which contains all
the options processed since those non-options were skipped.
'first_nonopt' and 'last_nonopt' are relocated so that they describe
the new indices of the non-options in ARGV after they are moved. */
static void
exchange (char **argv, struct _getopt_data *d)
{
int bottom = d->__first_nonopt;
int middle = d->__last_nonopt;
int top = d->optind;
char *tem;
/* Exchange the shorter segment with the far end of the longer segment.
That puts the shorter segment into the right place.
It leaves the longer segment in the right place overall,
but it consists of two parts that need to be swapped next. */
while (top > middle && middle > bottom)
{
if (top - middle > middle - bottom)
{
/* Bottom segment is the short one. */
int len = middle - bottom;
int i;
/* Swap it with the top part of the top segment. */
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[top - (middle - bottom) + i];
argv[top - (middle - bottom) + i] = tem;
}
/* Exclude the moved bottom segment from further swapping. */
top -= len;
}
else
{
/* Top segment is the short one. */
int len = top - middle;
int i;
/* Swap it with the bottom part of the bottom segment. */
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[middle + i];
argv[middle + i] = tem;
}
/* Exclude the moved top segment from further swapping. */
bottom += len;
}
}
/* Update records for the slots the non-options now occupy. */
d->__first_nonopt += (d->optind - d->__last_nonopt);
d->__last_nonopt = d->optind;
}
/* Process the argument starting with d->__nextchar as a long option.
d->optind should *not* have been advanced over this argument.
If the value returned is -1, it was not actually a long option, the
state is unchanged, and the argument should be processed as a set
of short options (this can only happen when long_only is true).
Otherwise, the option (and its argument, if any) have been consumed
and the return value is the value to return from _getopt_internal_r. */
static int
process_long_option (int argc, char **argv, const char *optstring,
const struct option *longopts, int *longind,
int long_only, struct _getopt_data *d,
int print_errors, const char *prefix)
{
char *nameend;
size_t namelen;
const struct option *p;
const struct option *pfound = NULL;
int n_options;
int option_index = 0;
for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++)
/* Do nothing. */ ;
namelen = nameend - d->__nextchar;
/* First look for an exact match, counting the options as a side
effect. */
for (p = longopts, n_options = 0; p->name; p++, n_options++)
if (!strncmp (p->name, d->__nextchar, namelen)
&& namelen == strlen (p->name))
{
/* Exact match found. */
pfound = p;
option_index = n_options;
break;
}
if (pfound == NULL)
{
/* Didn't find an exact match, so look for abbreviations. */
unsigned char *ambig_set = NULL;
int ambig_malloced = 0;
int ambig_fallback = 0;
int indfound = -1;
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!strncmp (p->name, d->__nextchar, namelen))
{
if (pfound == NULL)
{
/* First nonexact match found. */
pfound = p;
indfound = option_index;
}
else if (long_only
|| pfound->has_arg != p->has_arg
|| pfound->flag != p->flag
|| pfound->val != p->val)
{
/* Second or later nonexact match found. */
if (!ambig_fallback)
{
if (!print_errors)
/* Don't waste effort tracking the ambig set if
we're not going to print it anyway. */
ambig_fallback = 1;
else if (!ambig_set)
{
if (__libc_use_alloca (n_options))
ambig_set = alloca (n_options);
else if ((ambig_set = malloc (n_options)) == NULL)
/* Fall back to simpler error message. */
ambig_fallback = 1;
else
ambig_malloced = 1;
if (ambig_set)
{
memset (ambig_set, 0, n_options);
ambig_set[indfound] = 1;
}
}
if (ambig_set)
ambig_set[option_index] = 1;
}
}
}
if (ambig_set || ambig_fallback)
{
if (print_errors)
{
if (ambig_fallback)
fprintf (stderr, _("%s: option '%s%s' is ambiguous\n"),
argv[0], prefix, d->__nextchar);
else
{
flockfile (stderr);
fprintf (stderr,
_("%s: option '%s%s' is ambiguous; possibilities:"),
argv[0], prefix, d->__nextchar);
for (option_index = 0; option_index < n_options; option_index++)
if (ambig_set[option_index])
fprintf (stderr, " '%s%s'",
prefix, longopts[option_index].name);
/* This must use 'fprintf' even though it's only
printing a single character, so that it goes through
__fxprintf_nocancel when compiled as part of glibc. */
fprintf (stderr, "\n");
funlockfile (stderr);
}
}
if (ambig_malloced)
free (ambig_set);
d->__nextchar += strlen (d->__nextchar);
d->optind++;
d->optopt = 0;
return '?';
}
option_index = indfound;
}
if (pfound == NULL)
{
/* Can't find it as a long option. If this is not getopt_long_only,
or the option starts with '--' or is not a valid short option,
then it's an error. */
if (!long_only || argv[d->optind][1] == '-'
|| strchr (optstring, *d->__nextchar) == NULL)
{
if (print_errors)
fprintf (stderr, _("%s: unrecognized option '%s%s'\n"),
argv[0], prefix, d->__nextchar);
d->__nextchar = NULL;
d->optind++;
d->optopt = 0;
return '?';
}
/* Otherwise interpret it as a short option. */
return -1;
}
/* We have found a matching long option. Consume it. */
d->optind++;
d->__nextchar = NULL;
if (*nameend)
{
/* Don't test has_arg with >, because some C compilers don't
allow it to be used on enums. */
if (pfound->has_arg)
d->optarg = nameend + 1;
else
{
if (print_errors)
fprintf (stderr,
_("%s: option '%s%s' doesn't allow an argument\n"),
argv[0], prefix, pfound->name);
d->optopt = pfound->val;
return '?';
}
}
else if (pfound->has_arg == 1)
{
if (d->optind < argc)
d->optarg = argv[d->optind++];
else
{
if (print_errors)
fprintf (stderr,
_("%s: option '%s%s' requires an argument\n"),
argv[0], prefix, pfound->name);
d->optopt = pfound->val;
return optstring[0] == ':' ? ':' : '?';
}
}
if (longind != NULL)
*longind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
/* Initialize internal data upon the first call to getopt. */
static const char *
_getopt_initialize (_GL_UNUSED int argc,
_GL_UNUSED char **argv, const char *optstring,
struct _getopt_data *d, int posixly_correct)
{
/* Start processing options with ARGV-element 1 (since ARGV-element 0
is the program name); the sequence of previously skipped
non-option ARGV-elements is empty. */
if (d->optind == 0)
d->optind = 1;
d->__first_nonopt = d->__last_nonopt = d->optind;
d->__nextchar = NULL;
/* Determine how to handle the ordering of options and nonoptions. */
if (optstring[0] == '-')
{
d->__ordering = RETURN_IN_ORDER;
++optstring;
}
else if (optstring[0] == '+')
{
d->__ordering = REQUIRE_ORDER;
++optstring;
}
else if (posixly_correct || !!getenv ("POSIXLY_CORRECT"))
d->__ordering = REQUIRE_ORDER;
else
d->__ordering = PERMUTE;
d->__initialized = 1;
return optstring;
}
/* Scan elements of ARGV (whose length is ARGC) for option characters
given in OPTSTRING.
If an element of ARGV starts with '-', and is not exactly "-" or "--",
then it is an option element. The characters of this element
(aside from the initial '-') are option characters. If 'getopt'
is called repeatedly, it returns successively each of the option characters
from each of the option elements.
If 'getopt' finds another option character, it returns that character,
updating 'optind' and 'nextchar' so that the next call to 'getopt' can
resume the scan with the following option character or ARGV-element.
If there are no more option characters, 'getopt' returns -1.
Then 'optind' is the index in ARGV of the first ARGV-element
that is not an option. (The ARGV-elements have been permuted
so that those that are not options now come last.)
OPTSTRING is a string containing the legitimate option characters.
If an option character is seen that is not listed in OPTSTRING,
return '?' after printing an error message. If you set 'opterr' to
zero, the error message is suppressed but we still return '?'.
If a char in OPTSTRING is followed by a colon, that means it wants an arg,
so the following text in the same ARGV-element, or the text of the following
ARGV-element, is returned in 'optarg'. Two colons mean an option that
wants an optional arg; if there is text in the current ARGV-element,
it is returned in 'optarg', otherwise 'optarg' is set to zero.
If OPTSTRING starts with '-' or '+', it requests different methods of
handling the non-option ARGV-elements.
See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
Long-named options begin with '--' instead of '-'.
Their names may be abbreviated as long as the abbreviation is unique
or is an exact match for some defined option. If they have an
argument, it follows the option name in the same ARGV-element, separated
from the option name by a '=', or else the in next ARGV-element.
When 'getopt' finds a long-named option, it returns 0 if that option's
'flag' field is nonzero, the value of the option's 'val' field
if the 'flag' field is zero.
The elements of ARGV aren't really const, because we permute them.
But we pretend they're const in the prototype to be compatible
with other systems.
LONGOPTS is a vector of 'struct option' terminated by an
element containing a name which is zero.
LONGIND returns the index in LONGOPT of the long-named option found.
It is only valid when a long-named option has been found by the most
recent call.
If LONG_ONLY is nonzero, '-' as well as '--' can introduce
long-named options. */
int
_getopt_internal_r (int argc, char **argv, const char *optstring,
const struct option *longopts, int *longind,
int long_only, struct _getopt_data *d, int posixly_correct)
{
int print_errors = d->opterr;
if (argc < 1)
return -1;
d->optarg = NULL;
if (d->optind == 0 || !d->__initialized)
optstring = _getopt_initialize (argc, argv, optstring, d, posixly_correct);
else if (optstring[0] == '-' || optstring[0] == '+')
optstring++;
if (optstring[0] == ':')
print_errors = 0;
/* Test whether ARGV[optind] points to a non-option argument. */
#define NONOPTION_P (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0')
if (d->__nextchar == NULL || *d->__nextchar == '\0')
{
/* Advance to the next ARGV-element. */
/* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
moved back by the user (who may also have changed the arguments). */
if (d->__last_nonopt > d->optind)
d->__last_nonopt = d->optind;
if (d->__first_nonopt > d->optind)
d->__first_nonopt = d->optind;
if (d->__ordering == PERMUTE)
{
/* If we have just processed some options following some non-options,
exchange them so that the options come first. */
if (d->__first_nonopt != d->__last_nonopt
&& d->__last_nonopt != d->optind)
exchange (argv, d);
else if (d->__last_nonopt != d->optind)
d->__first_nonopt = d->optind;
/* Skip any additional non-options
and extend the range of non-options previously skipped. */
while (d->optind < argc && NONOPTION_P)
d->optind++;
d->__last_nonopt = d->optind;
}
/* The special ARGV-element '--' means premature end of options.
Skip it like a null option,
then exchange with previous non-options as if it were an option,
then skip everything else like a non-option. */
if (d->optind != argc && !strcmp (argv[d->optind], "--"))
{
d->optind++;
if (d->__first_nonopt != d->__last_nonopt
&& d->__last_nonopt != d->optind)
exchange (argv, d);
else if (d->__first_nonopt == d->__last_nonopt)
d->__first_nonopt = d->optind;
d->__last_nonopt = argc;
d->optind = argc;
}
/* If we have done all the ARGV-elements, stop the scan
and back over any non-options that we skipped and permuted. */
if (d->optind == argc)
{
/* Set the next-arg-index to point at the non-options
that we previously skipped, so the caller will digest them. */
if (d->__first_nonopt != d->__last_nonopt)
d->optind = d->__first_nonopt;
return -1;
}
/* If we have come to a non-option and did not permute it,
either stop the scan or describe it to the caller and pass it by. */
if (NONOPTION_P)
{
if (d->__ordering == REQUIRE_ORDER)
return -1;
d->optarg = argv[d->optind++];
return 1;
}
/* We have found another option-ARGV-element.
Check whether it might be a long option. */
if (longopts)
{
if (argv[d->optind][1] == '-')
{
/* "--foo" is always a long option. The special option
"--" was handled above. */
d->__nextchar = argv[d->optind] + 2;
return process_long_option (argc, argv, optstring, longopts,
longind, long_only, d,
print_errors, "--");
}
/* If long_only and the ARGV-element has the form "-f",
where f is a valid short option, don't consider it an
abbreviated form of a long option that starts with f.
Otherwise there would be no way to give the -f short
option.
On the other hand, if there's a long option "fubar" and
the ARGV-element is "-fu", do consider that an
abbreviation of the long option, just like "--fu", and
not "-f" with arg "u".
This distinction seems to be the most useful approach. */
if (long_only && (argv[d->optind][2]
|| !strchr (optstring, argv[d->optind][1])))
{
int code;
d->__nextchar = argv[d->optind] + 1;
code = process_long_option (argc, argv, optstring, longopts,
longind, long_only, d,
print_errors, "-");
if (code != -1)
return code;
}
}
/* It is not a long option. Skip the initial punctuation. */
d->__nextchar = argv[d->optind] + 1;
}
/* Look at and handle the next short option-character. */
{
char c = *d->__nextchar++;
const char *temp = strchr (optstring, c);
/* Increment 'optind' when we start to process its last character. */
if (*d->__nextchar == '\0')
++d->optind;
if (temp == NULL || c == ':' || c == ';')
{
if (print_errors)
fprintf (stderr, _("%s: invalid option -- '%c'\n"), argv[0], c);
d->optopt = c;
return '?';
}
/* Convenience. Treat POSIX -W foo same as long option --foo */
if (temp[0] == 'W' && temp[1] == ';' && longopts != NULL)
{
/* This is an option that requires an argument. */
if (*d->__nextchar != '\0')
d->optarg = d->__nextchar;
else if (d->optind == argc)
{
if (print_errors)
fprintf (stderr,
_("%s: option requires an argument -- '%c'\n"),
argv[0], c);
d->optopt = c;
if (optstring[0] == ':')
c = ':';
else
c = '?';
return c;
}
else
d->optarg = argv[d->optind];
d->__nextchar = d->optarg;
d->optarg = NULL;
return process_long_option (argc, argv, optstring, longopts, longind,
0 /* long_only */, d, print_errors, "-W ");
}
if (temp[1] == ':')
{
if (temp[2] == ':')
{
/* This is an option that accepts an argument optionally. */
if (*d->__nextchar != '\0')
{
d->optarg = d->__nextchar;
d->optind++;
}
else
d->optarg = NULL;
d->__nextchar = NULL;
}
else
{
/* This is an option that requires an argument. */
if (*d->__nextchar != '\0')
{
d->optarg = d->__nextchar;
/* If we end this ARGV-element by taking the rest as an arg,
we must advance to the next element now. */
d->optind++;
}
else if (d->optind == argc)
{
if (print_errors)
fprintf (stderr,
_("%s: option requires an argument -- '%c'\n"),
argv[0], c);
d->optopt = c;
if (optstring[0] == ':')
c = ':';
else
c = '?';
}
else
/* We already incremented 'optind' once;
increment it again when taking next ARGV-elt as argument. */
d->optarg = argv[d->optind++];
d->__nextchar = NULL;
}
}
return c;
}
}
int
_getopt_internal (int argc, char **argv, const char *optstring,
const struct option *longopts, int *longind, int long_only,
int posixly_correct)
{
int result;
getopt_data.optind = optind;
getopt_data.opterr = opterr;
result = _getopt_internal_r (argc, argv, optstring, longopts,
longind, long_only, &getopt_data,
posixly_correct);
optind = getopt_data.optind;
optarg = getopt_data.optarg;
optopt = getopt_data.optopt;
return result;
}
/* glibc gets a LSB-compliant getopt and a POSIX-complaint __posix_getopt.
Standalone applications just get a POSIX-compliant getopt.
POSIX and LSB both require these functions to take 'char *const *argv'
even though this is incorrect (because of the permutation). */
#define GETOPT_ENTRY(NAME, POSIXLY_CORRECT) \
int \
NAME (int argc, char *const *argv, const char *optstring) \
{ \
return _getopt_internal (argc, (char **)argv, optstring, \
NULL, NULL, 0, POSIXLY_CORRECT); \
}
#ifdef _LIBC
GETOPT_ENTRY(getopt, 0)
GETOPT_ENTRY(__posix_getopt, 1)
#else
GETOPT_ENTRY(getopt, 1)
#endif
#ifdef TEST
/* Compile with -DTEST to make an executable for use in testing
the above definition of 'getopt'. */
int
main (int argc, char **argv)
{
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
c = getopt (argc, argv, "abc:d:0123456789");
if (c == -1)
break;
switch (c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case 'a':
printf ("option a\n");
break;
case 'b':
printf ("option b\n");
break;
case 'c':
printf ("option c with value '%s'\n", optarg);
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
exit (0);
}
#endif /* TEST */
@@ -0,0 +1,38 @@
/* Declarations for getopt.
Copyright (C) 1989-2026 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Unlike the bulk of the getopt implementation, this file is NOT part
of gnulib; gnulib also has a getopt.h but it is different.
The GNU C 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.
The GNU C 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 the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#ifndef _GETOPT_H
#define _GETOPT_H 1
#include <features.h>
/* The type of the 'argv' argument to getopt_long and getopt_long_only
is properly 'char **', since both functions may write to the array
(in order to move all the options to the beginning). However, for
compatibility with old versions of LSB, glibc has to use 'char *const *'
instead. */
#ifndef __getopt_argv_const
# define __getopt_argv_const const
#endif
#include <bits/getopt_core.h>
#include <bits/getopt_ext.h>
#endif /* getopt.h */
@@ -0,0 +1,159 @@
/* getopt_long and getopt_long_only entry points for GNU getopt.
Copyright (C) 1987-2026 Free Software Foundation, Inc.
This file is part of the GNU C Library and is also part of gnulib.
Patches to this file should be submitted to both projects.
The GNU C 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.
The GNU C 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 the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#ifndef _LIBC
# include <config.h>
#endif
#include "getopt.h"
#include "getopt_int.h"
int
getopt_long (int argc, char *__getopt_argv_const *argv, const char *options,
const struct option *long_options, int *opt_index)
{
return _getopt_internal (argc, (char **) argv, options, long_options,
opt_index, 0, 0);
}
int
_getopt_long_r (int argc, char **argv, const char *options,
const struct option *long_options, int *opt_index,
struct _getopt_data *d)
{
return _getopt_internal_r (argc, argv, options, long_options, opt_index,
0, d, 0);
}
/* Like getopt_long, but '-' as well as '--' can indicate a long option.
If an option that starts with '-' (not '--') doesn't match a long option,
but does match a short option, it is parsed as a short option
instead. */
int
getopt_long_only (int argc, char *__getopt_argv_const *argv,
const char *options,
const struct option *long_options, int *opt_index)
{
return _getopt_internal (argc, (char **) argv, options, long_options,
opt_index, 1, 0);
}
int
_getopt_long_only_r (int argc, char **argv, const char *options,
const struct option *long_options, int *opt_index,
struct _getopt_data *d)
{
return _getopt_internal_r (argc, argv, options, long_options, opt_index,
1, d, 0);
}
#ifdef TEST
#include <stdio.h>
#include <stdlib.h>
int
main (int argc, char **argv)
{
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
int option_index = 0;
static const struct option long_options[] =
{
{"add", 1, 0, 0},
{"append", 0, 0, 0},
{"delete", 1, 0, 0},
{"verbose", 0, 0, 0},
{"create", 0, 0, 0},
{"file", 1, 0, 0},
{0, 0, 0, 0}
};
c = getopt_long (argc, argv, "abc:d:0123456789",
long_options, &option_index);
if (c == -1)
break;
switch (c)
{
case 0:
printf ("option %s", long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case 'a':
printf ("option a\n");
break;
case 'b':
printf ("option b\n");
break;
case 'c':
printf ("option c with value '%s'\n", optarg);
break;
case 'd':
printf ("option d with value '%s'\n", optarg);
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
exit (0);
}
#endif /* TEST */
@@ -0,0 +1,118 @@
/* Internal declarations for getopt.
Copyright (C) 1989-2026 Free Software Foundation, Inc.
This file is part of the GNU C Library and is also part of gnulib.
Patches to this file should be submitted to both projects.
The GNU C 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.
The GNU C 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 the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#ifndef _GETOPT_INT_H
#define _GETOPT_INT_H 1
#include <getopt.h>
extern int _getopt_internal (int ___argc, char **___argv,
const char *__shortopts,
const struct option *__longopts, int *__longind,
int __long_only, int __posixly_correct);
/* Reentrant versions which can handle parsing multiple argument
vectors at the same time. */
/* Describe how to deal with options that follow non-option ARGV-elements.
REQUIRE_ORDER means don't recognize them as options; stop option
processing when the first non-option is seen. This is what POSIX
specifies should happen.
PERMUTE means permute the contents of ARGV as we scan, so that
eventually all the non-options are at the end. This allows options
to be given in any order, even with programs that were not written
to expect this.
RETURN_IN_ORDER is an option available to programs that were
written to expect options and other ARGV-elements in any order
and that care about the ordering of the two. We describe each
non-option ARGV-element as if it were the argument of an option
with character code 1.
The special argument '--' forces an end of option-scanning regardless
of the value of 'ordering'. In the case of RETURN_IN_ORDER, only
'--' can cause 'getopt' to return -1 with 'optind' != ARGC. */
enum __ord
{
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
};
/* Data type for reentrant functions. */
struct _getopt_data
{
/* These have exactly the same meaning as the corresponding global
variables, except that they are used for the reentrant
versions of getopt. */
int optind;
int opterr;
int optopt;
char *optarg;
/* Internal members. */
/* True if the internal members have been initialized. */
int __initialized;
/* The next char to be scanned in the option-element
in which the last option character we returned was found.
This allows us to pick up the scan where we left off.
If this is zero, or a null string, it means resume the scan
by advancing to the next ARGV-element. */
char *__nextchar;
/* See __ord above. */
enum __ord __ordering;
/* Handle permutation of arguments. */
/* Describe the part of ARGV that contains non-options that have
been skipped. 'first_nonopt' is the index in ARGV of the first
of them; 'last_nonopt' is the index after the last of them. */
int __first_nonopt;
int __last_nonopt;
};
/* The initializer is necessary to set OPTIND and OPTERR to their
default values and to clear the initialization flag. */
#define _GETOPT_DATA_INITIALIZER { 1, 1 }
extern int _getopt_internal_r (int ___argc, char **___argv,
const char *__shortopts,
const struct option *__longopts, int *__longind,
int __long_only, struct _getopt_data *__data,
int __posixly_correct);
extern int _getopt_long_r (int ___argc, char **___argv,
const char *__shortopts,
const struct option *__longopts, int *__longind,
struct _getopt_data *__data);
extern int _getopt_long_only_r (int ___argc, char **___argv,
const char *__shortopts,
const struct option *__longopts,
int *__longind,
struct _getopt_data *__data);
#endif /* getopt_int.h */
@@ -0,0 +1,7 @@
/* Minimal gettext shim for standalone getopt build on MSVC. */
#ifndef _GETTEXT_H
#define _GETTEXT_H 1
#define gettext(msgid) (msgid)
#endif /* _GETTEXT_H */
@@ -0,0 +1,5 @@
/* Minimal unistd.h shim for standalone getopt build on MSVC. */
#ifndef _UNISTD_H
#define _UNISTD_H 1
#endif /* _UNISTD_H */
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="ProjectConfigurations.Base.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{99D2AC64-DC66-4422-91CE-6715C403C9E5}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="Configuration.Application.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="Base.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemGroup>
<ClCompile Include="..\examples\hotplugtest.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\libusb\libusb.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include=".\libusb_static.vcxproj">
<Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="ProjectConfigurations.Base.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="Configuration.Application.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="Base.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemGroup>
<ClCompile Include="..\tests\init_context.c" />
<ClCompile Include="..\tests\testlib.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include=".\config.h" />
<ClInclude Include="..\libusb\libusb.h" />
<ClInclude Include="..\tests\libusb_testlib.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include=".\libusb_static.vcxproj">
<Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,789 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.32112.339
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb_static", "libusb_static.vcxproj", "{349EE8F9-7D25-4909-AAF5-FF3FADE72187}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb_dll", "libusb_dll.vcxproj", "{349EE8FA-7D25-4909-AAF5-FF3FADE72187}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dpfp", "dpfp.vcxproj", "{8C7814A1-FD6E-4185-9EA0-8208119756D4}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dpfp_threaded", "dpfp_threaded.vcxproj", "{8C7814A2-FD6E-4185-9EA0-8208119756D4}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fxload", "fxload.vcxproj", "{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "getopt", "getopt.vcxproj", "{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hotplugtest", "hotplugtest.vcxproj", "{99D2AC64-DC66-4422-91CE-6715C403C9E5}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "init_context", "init_context.vcxproj", "{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "listdevs", "listdevs.vcxproj", "{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sam3u_benchmark", "sam3u_benchmark.vcxproj", "{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stress", "stress.vcxproj", "{53942EFF-C810-458D-B3CB-EE5CE9F1E781}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stress_mt", "stress_mt.vcxproj", "{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testlibusb", "testlibusb.vcxproj", "{70828935-325B-4749-B381-0E55EF31AEE8}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xusb", "xusb.vcxproj", "{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "set_option", "set_option.vcxproj", "{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Debug-Hotplug|ARM64 = Debug-Hotplug|ARM64
Debug-Hotplug|Win32 = Debug-Hotplug|Win32
Debug-Hotplug|x64 = Debug-Hotplug|x64
Debug-Hotplug-MT|ARM64 = Debug-Hotplug-MT|ARM64
Debug-Hotplug-MT|Win32 = Debug-Hotplug-MT|Win32
Debug-Hotplug-MT|x64 = Debug-Hotplug-MT|x64
Debug-MT|ARM64 = Debug-MT|ARM64
Debug-MT|Win32 = Debug-MT|Win32
Debug-MT|x64 = Debug-MT|x64
Release|ARM64 = Release|ARM64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
Release-Hotplug|ARM64 = Release-Hotplug|ARM64
Release-Hotplug|Win32 = Release-Hotplug|Win32
Release-Hotplug|x64 = Release-Hotplug|x64
Release-Hotplug-MT|ARM64 = Release-Hotplug-MT|ARM64
Release-Hotplug-MT|Win32 = Release-Hotplug-MT|Win32
Release-Hotplug-MT|x64 = Release-Hotplug-MT|x64
Release-MT|ARM64 = Release-MT|ARM64
Release-MT|Win32 = Release-MT|Win32
Release-MT|x64 = Release-MT|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|ARM64.ActiveCfg = Debug|ARM64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|ARM64.Build.0 = Debug|ARM64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|Win32.ActiveCfg = Debug|Win32
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|Win32.Build.0 = Debug|Win32
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.ActiveCfg = Debug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.Build.0 = Debug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug-Hotplug|ARM64.ActiveCfg = Debug-Hotplug|ARM64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug-Hotplug|ARM64.Build.0 = Debug-Hotplug|ARM64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug-Hotplug|Win32.ActiveCfg = Debug-Hotplug|Win32
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug-Hotplug|Win32.Build.0 = Debug-Hotplug|Win32
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug-Hotplug|x64.ActiveCfg = Debug-Hotplug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug-Hotplug|x64.Build.0 = Debug-Hotplug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug-Hotplug-MT|ARM64.ActiveCfg = Debug-Hotplug-MT|ARM64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug-Hotplug-MT|ARM64.Build.0 = Debug-Hotplug-MT|ARM64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug-Hotplug-MT|Win32.ActiveCfg = Debug-Hotplug-MT|Win32
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug-Hotplug-MT|Win32.Build.0 = Debug-Hotplug-MT|Win32
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug-Hotplug-MT|x64.ActiveCfg = Debug-Hotplug-MT|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug-Hotplug-MT|x64.Build.0 = Debug-Hotplug-MT|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug-MT|ARM64.ActiveCfg = Debug-MT|ARM64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug-MT|ARM64.Build.0 = Debug-MT|ARM64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug-MT|Win32.ActiveCfg = Debug-MT|Win32
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug-MT|Win32.Build.0 = Debug-MT|Win32
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug-MT|x64.ActiveCfg = Debug-MT|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug-MT|x64.Build.0 = Debug-MT|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|ARM64.ActiveCfg = Release|ARM64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|ARM64.Build.0 = Release|ARM64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|Win32.ActiveCfg = Release|Win32
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|Win32.Build.0 = Release|Win32
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x64.ActiveCfg = Release|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x64.Build.0 = Release|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release-Hotplug|ARM64.ActiveCfg = Release-Hotplug|ARM64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release-Hotplug|ARM64.Build.0 = Release-Hotplug|ARM64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release-Hotplug|Win32.ActiveCfg = Release-Hotplug|Win32
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release-Hotplug|Win32.Build.0 = Release-Hotplug|Win32
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release-Hotplug|x64.ActiveCfg = Release-Hotplug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release-Hotplug|x64.Build.0 = Release-Hotplug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release-Hotplug-MT|ARM64.ActiveCfg = Release-Hotplug-MT|ARM64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release-Hotplug-MT|ARM64.Build.0 = Release-Hotplug-MT|ARM64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release-Hotplug-MT|Win32.ActiveCfg = Release-Hotplug-MT|Win32
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release-Hotplug-MT|Win32.Build.0 = Release-Hotplug-MT|Win32
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release-Hotplug-MT|x64.ActiveCfg = Release-Hotplug-MT|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release-Hotplug-MT|x64.Build.0 = Release-Hotplug-MT|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release-MT|ARM64.ActiveCfg = Release-MT|ARM64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release-MT|ARM64.Build.0 = Release-MT|ARM64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release-MT|Win32.ActiveCfg = Release-MT|Win32
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release-MT|Win32.Build.0 = Release-MT|Win32
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release-MT|x64.ActiveCfg = Release-MT|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release-MT|x64.Build.0 = Release-MT|x64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug|ARM64.ActiveCfg = Debug|ARM64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug|ARM64.Build.0 = Debug|ARM64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug|Win32.ActiveCfg = Debug|Win32
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug|Win32.Build.0 = Debug|Win32
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.ActiveCfg = Debug|x64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.Build.0 = Debug|x64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug-Hotplug|ARM64.ActiveCfg = Debug-Hotplug|ARM64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug-Hotplug|ARM64.Build.0 = Debug-Hotplug|ARM64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug-Hotplug|Win32.ActiveCfg = Debug-Hotplug|Win32
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug-Hotplug|Win32.Build.0 = Debug-Hotplug|Win32
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug-Hotplug|x64.ActiveCfg = Debug-Hotplug|x64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug-Hotplug|x64.Build.0 = Debug-Hotplug|x64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug-Hotplug-MT|ARM64.ActiveCfg = Debug-Hotplug-MT|ARM64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug-Hotplug-MT|ARM64.Build.0 = Debug-Hotplug-MT|ARM64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug-Hotplug-MT|Win32.ActiveCfg = Debug-Hotplug-MT|Win32
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug-Hotplug-MT|Win32.Build.0 = Debug-Hotplug-MT|Win32
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug-Hotplug-MT|x64.ActiveCfg = Debug-Hotplug-MT|x64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug-Hotplug-MT|x64.Build.0 = Debug-Hotplug-MT|x64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug-MT|ARM64.ActiveCfg = Debug-MT|ARM64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug-MT|ARM64.Build.0 = Debug-MT|ARM64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug-MT|Win32.ActiveCfg = Debug-MT|Win32
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug-MT|Win32.Build.0 = Debug-MT|Win32
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug-MT|x64.ActiveCfg = Debug-MT|x64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug-MT|x64.Build.0 = Debug-MT|x64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release|ARM64.ActiveCfg = Release|ARM64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release|ARM64.Build.0 = Release|ARM64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release|Win32.ActiveCfg = Release|Win32
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release|Win32.Build.0 = Release|Win32
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release|x64.ActiveCfg = Release|x64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release|x64.Build.0 = Release|x64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release-Hotplug|ARM64.ActiveCfg = Release-Hotplug|ARM64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release-Hotplug|ARM64.Build.0 = Release-Hotplug|ARM64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release-Hotplug|Win32.ActiveCfg = Release-Hotplug|Win32
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release-Hotplug|Win32.Build.0 = Release-Hotplug|Win32
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release-Hotplug|x64.ActiveCfg = Release-Hotplug|x64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release-Hotplug|x64.Build.0 = Release-Hotplug|x64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release-Hotplug-MT|ARM64.ActiveCfg = Release-Hotplug-MT|ARM64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release-Hotplug-MT|ARM64.Build.0 = Release-Hotplug-MT|ARM64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release-Hotplug-MT|Win32.ActiveCfg = Release-Hotplug-MT|Win32
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release-Hotplug-MT|Win32.Build.0 = Release-Hotplug-MT|Win32
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release-Hotplug-MT|x64.ActiveCfg = Release-Hotplug-MT|x64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release-Hotplug-MT|x64.Build.0 = Release-Hotplug-MT|x64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release-MT|ARM64.ActiveCfg = Release-MT|ARM64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release-MT|ARM64.Build.0 = Release-MT|ARM64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release-MT|Win32.ActiveCfg = Release-MT|Win32
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release-MT|Win32.Build.0 = Release-MT|Win32
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release-MT|x64.ActiveCfg = Release-MT|x64
{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release-MT|x64.Build.0 = Release-MT|x64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|ARM64.ActiveCfg = Debug|ARM64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|ARM64.Build.0 = Debug|ARM64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|Win32.ActiveCfg = Debug|Win32
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|Win32.Build.0 = Debug|Win32
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|x64.ActiveCfg = Debug|x64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug|x64.Build.0 = Debug|x64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug-Hotplug|ARM64.ActiveCfg = Debug-Hotplug|ARM64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug-Hotplug|ARM64.Build.0 = Debug-Hotplug|ARM64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug-Hotplug|Win32.ActiveCfg = Debug-Hotplug|Win32
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug-Hotplug|Win32.Build.0 = Debug-Hotplug|Win32
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug-Hotplug|x64.ActiveCfg = Debug-Hotplug|x64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug-Hotplug|x64.Build.0 = Debug-Hotplug|x64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug-Hotplug-MT|ARM64.ActiveCfg = Debug-Hotplug-MT|ARM64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug-Hotplug-MT|ARM64.Build.0 = Debug-Hotplug-MT|ARM64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug-Hotplug-MT|Win32.ActiveCfg = Debug-Hotplug-MT|Win32
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug-Hotplug-MT|Win32.Build.0 = Debug-Hotplug-MT|Win32
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug-Hotplug-MT|x64.ActiveCfg = Debug-Hotplug-MT|x64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug-MT|ARM64.ActiveCfg = Debug-MT|ARM64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug-MT|ARM64.Build.0 = Debug-MT|ARM64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug-MT|Win32.ActiveCfg = Debug-MT|Win32
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug-MT|Win32.Build.0 = Debug-MT|Win32
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug-MT|x64.ActiveCfg = Debug-MT|x64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Debug-MT|x64.Build.0 = Debug-MT|x64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|ARM64.ActiveCfg = Release|ARM64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|ARM64.Build.0 = Release|ARM64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|Win32.ActiveCfg = Release|Win32
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|Win32.Build.0 = Release|Win32
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|x64.ActiveCfg = Release|x64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release|x64.Build.0 = Release|x64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release-Hotplug|ARM64.ActiveCfg = Release-Hotplug|ARM64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release-Hotplug|ARM64.Build.0 = Release-Hotplug|ARM64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release-Hotplug|Win32.ActiveCfg = Release-Hotplug|Win32
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release-Hotplug|Win32.Build.0 = Release-Hotplug|Win32
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release-Hotplug|x64.ActiveCfg = Release-Hotplug|x64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release-Hotplug|x64.Build.0 = Release-Hotplug|x64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release-Hotplug-MT|ARM64.ActiveCfg = Release-Hotplug-MT|ARM64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release-Hotplug-MT|ARM64.Build.0 = Release-Hotplug-MT|ARM64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release-Hotplug-MT|Win32.ActiveCfg = Release-Hotplug-MT|Win32
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release-Hotplug-MT|Win32.Build.0 = Release-Hotplug-MT|Win32
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release-Hotplug-MT|x64.ActiveCfg = Release-Hotplug-MT|x64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release-Hotplug-MT|x64.Build.0 = Release-Hotplug-MT|x64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release-MT|ARM64.ActiveCfg = Release-MT|ARM64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release-MT|ARM64.Build.0 = Release-MT|ARM64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release-MT|Win32.ActiveCfg = Release-MT|Win32
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release-MT|Win32.Build.0 = Release-MT|Win32
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release-MT|x64.ActiveCfg = Release-MT|x64
{8C7814A1-FD6E-4185-9EA0-8208119756D4}.Release-MT|x64.Build.0 = Release-MT|x64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|ARM64.ActiveCfg = Debug|ARM64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|ARM64.Build.0 = Debug|ARM64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|Win32.ActiveCfg = Debug|Win32
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|Win32.Build.0 = Debug|Win32
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|x64.ActiveCfg = Debug|x64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug|x64.Build.0 = Debug|x64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug-Hotplug|ARM64.ActiveCfg = Debug-Hotplug|ARM64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug-Hotplug|ARM64.Build.0 = Debug-Hotplug|ARM64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug-Hotplug|Win32.ActiveCfg = Debug-Hotplug|Win32
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug-Hotplug|Win32.Build.0 = Debug-Hotplug|Win32
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug-Hotplug|x64.ActiveCfg = Debug-Hotplug|x64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug-Hotplug|x64.Build.0 = Debug-Hotplug|x64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug-Hotplug-MT|ARM64.ActiveCfg = Debug-Hotplug-MT|ARM64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug-Hotplug-MT|ARM64.Build.0 = Debug-Hotplug-MT|ARM64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug-Hotplug-MT|Win32.ActiveCfg = Debug-Hotplug-MT|Win32
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug-Hotplug-MT|Win32.Build.0 = Debug-Hotplug-MT|Win32
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug-Hotplug-MT|x64.ActiveCfg = Debug-Hotplug-MT|x64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug-Hotplug-MT|x64.Build.0 = Debug-Hotplug-MT|x64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug-MT|ARM64.ActiveCfg = Debug-MT|ARM64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug-MT|ARM64.Build.0 = Debug-MT|ARM64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug-MT|Win32.ActiveCfg = Debug-MT|Win32
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug-MT|Win32.Build.0 = Debug-MT|Win32
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug-MT|x64.ActiveCfg = Debug-MT|x64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Debug-MT|x64.Build.0 = Debug-MT|x64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|ARM64.ActiveCfg = Release|ARM64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|ARM64.Build.0 = Release|ARM64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|Win32.ActiveCfg = Release|Win32
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|Win32.Build.0 = Release|Win32
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|x64.ActiveCfg = Release|x64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release|x64.Build.0 = Release|x64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release-Hotplug|ARM64.ActiveCfg = Release-Hotplug|ARM64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release-Hotplug|ARM64.Build.0 = Release-Hotplug|ARM64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release-Hotplug|Win32.ActiveCfg = Release-Hotplug|Win32
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release-Hotplug|Win32.Build.0 = Release-Hotplug|Win32
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release-Hotplug|x64.ActiveCfg = Release-Hotplug|x64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release-Hotplug|x64.Build.0 = Release-Hotplug|x64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release-Hotplug-MT|ARM64.ActiveCfg = Release-Hotplug-MT|ARM64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release-Hotplug-MT|ARM64.Build.0 = Release-Hotplug-MT|ARM64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release-Hotplug-MT|Win32.ActiveCfg = Release-Hotplug-MT|Win32
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release-Hotplug-MT|Win32.Build.0 = Release-Hotplug-MT|Win32
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release-Hotplug-MT|x64.ActiveCfg = Release-Hotplug-MT|x64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release-Hotplug-MT|x64.Build.0 = Release-Hotplug-MT|x64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release-MT|ARM64.ActiveCfg = Release-MT|ARM64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release-MT|ARM64.Build.0 = Release-MT|ARM64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release-MT|Win32.ActiveCfg = Release-MT|Win32
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release-MT|Win32.Build.0 = Release-MT|Win32
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release-MT|x64.ActiveCfg = Release-MT|x64
{8C7814A2-FD6E-4185-9EA0-8208119756D4}.Release-MT|x64.Build.0 = Release-MT|x64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug|ARM64.ActiveCfg = Debug|ARM64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug|ARM64.Build.0 = Debug|ARM64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug|Win32.ActiveCfg = Debug|Win32
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug|Win32.Build.0 = Debug|Win32
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug|x64.ActiveCfg = Debug|x64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug|x64.Build.0 = Debug|x64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug-Hotplug|ARM64.ActiveCfg = Debug-Hotplug|ARM64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug-Hotplug|ARM64.Build.0 = Debug-Hotplug|ARM64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug-Hotplug|Win32.ActiveCfg = Debug-Hotplug|Win32
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug-Hotplug|Win32.Build.0 = Debug-Hotplug|Win32
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug-Hotplug|x64.ActiveCfg = Debug-Hotplug|x64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug-Hotplug|x64.Build.0 = Debug-Hotplug|x64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug-Hotplug-MT|ARM64.ActiveCfg = Debug-Hotplug-MT|ARM64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug-Hotplug-MT|ARM64.Build.0 = Debug-Hotplug-MT|ARM64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug-Hotplug-MT|Win32.ActiveCfg = Debug-Hotplug-MT|Win32
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug-Hotplug-MT|Win32.Build.0 = Debug-Hotplug-MT|Win32
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug-Hotplug-MT|x64.ActiveCfg = Debug-Hotplug-MT|x64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug-Hotplug-MT|x64.Build.0 = Debug-Hotplug-MT|x64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug-MT|ARM64.ActiveCfg = Debug-MT|ARM64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug-MT|ARM64.Build.0 = Debug-MT|ARM64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug-MT|Win32.ActiveCfg = Debug-MT|Win32
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug-MT|Win32.Build.0 = Debug-MT|Win32
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug-MT|x64.ActiveCfg = Debug-MT|x64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug-MT|x64.Build.0 = Debug-MT|x64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release|ARM64.ActiveCfg = Release|ARM64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release|ARM64.Build.0 = Release|ARM64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release|Win32.ActiveCfg = Release|Win32
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release|Win32.Build.0 = Release|Win32
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release|x64.ActiveCfg = Release|x64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release|x64.Build.0 = Release|x64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release-Hotplug|ARM64.ActiveCfg = Release-Hotplug|ARM64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release-Hotplug|ARM64.Build.0 = Release-Hotplug|ARM64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release-Hotplug|Win32.ActiveCfg = Release-Hotplug|Win32
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release-Hotplug|Win32.Build.0 = Release-Hotplug|Win32
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release-Hotplug|x64.ActiveCfg = Release-Hotplug|x64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release-Hotplug|x64.Build.0 = Release-Hotplug|x64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release-Hotplug-MT|ARM64.ActiveCfg = Release-Hotplug-MT|ARM64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release-Hotplug-MT|ARM64.Build.0 = Release-Hotplug-MT|ARM64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release-Hotplug-MT|Win32.ActiveCfg = Release-Hotplug-MT|Win32
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release-Hotplug-MT|Win32.Build.0 = Release-Hotplug-MT|Win32
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release-Hotplug-MT|x64.ActiveCfg = Release-Hotplug-MT|x64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release-Hotplug-MT|x64.Build.0 = Release-Hotplug-MT|x64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release-MT|ARM64.ActiveCfg = Release-MT|ARM64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release-MT|ARM64.Build.0 = Release-MT|ARM64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release-MT|Win32.ActiveCfg = Release-MT|Win32
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release-MT|Win32.Build.0 = Release-MT|Win32
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release-MT|x64.ActiveCfg = Release-MT|x64
{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release-MT|x64.Build.0 = Release-MT|x64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|ARM64.ActiveCfg = Debug|ARM64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|ARM64.Build.0 = Debug|ARM64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|Win32.ActiveCfg = Debug|Win32
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|Win32.Build.0 = Debug|Win32
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|x64.ActiveCfg = Debug|x64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|x64.Build.0 = Debug|x64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug-Hotplug|ARM64.ActiveCfg = Debug-Hotplug|ARM64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug-Hotplug|ARM64.Build.0 = Debug-Hotplug|ARM64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug-Hotplug|Win32.ActiveCfg = Debug-Hotplug|Win32
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug-Hotplug|Win32.Build.0 = Debug-Hotplug|Win32
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug-Hotplug|x64.ActiveCfg = Debug-Hotplug|x64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug-Hotplug|x64.Build.0 = Debug-Hotplug|x64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug-Hotplug-MT|ARM64.ActiveCfg = Debug-Hotplug-MT|ARM64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug-Hotplug-MT|ARM64.Build.0 = Debug-Hotplug-MT|ARM64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug-Hotplug-MT|Win32.ActiveCfg = Debug-Hotplug-MT|Win32
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug-Hotplug-MT|Win32.Build.0 = Debug-Hotplug-MT|Win32
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug-Hotplug-MT|x64.ActiveCfg = Debug-Hotplug-MT|x64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug-Hotplug-MT|x64.Build.0 = Debug-Hotplug-MT|x64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug-MT|ARM64.ActiveCfg = Debug-MT|ARM64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug-MT|ARM64.Build.0 = Debug-MT|ARM64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug-MT|Win32.ActiveCfg = Debug-MT|Win32
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug-MT|Win32.Build.0 = Debug-MT|Win32
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug-MT|x64.ActiveCfg = Debug-MT|x64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug-MT|x64.Build.0 = Debug-MT|x64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|ARM64.ActiveCfg = Release|ARM64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|ARM64.Build.0 = Release|ARM64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|Win32.ActiveCfg = Release|Win32
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|Win32.Build.0 = Release|Win32
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|x64.ActiveCfg = Release|x64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|x64.Build.0 = Release|x64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release-Hotplug|ARM64.ActiveCfg = Release-Hotplug|ARM64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release-Hotplug|ARM64.Build.0 = Release-Hotplug|ARM64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release-Hotplug|Win32.ActiveCfg = Release-Hotplug|Win32
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release-Hotplug|Win32.Build.0 = Release-Hotplug|Win32
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release-Hotplug|x64.ActiveCfg = Release-Hotplug|x64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release-Hotplug|x64.Build.0 = Release-Hotplug|x64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release-Hotplug-MT|ARM64.ActiveCfg = Release-Hotplug-MT|ARM64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release-Hotplug-MT|ARM64.Build.0 = Release-Hotplug-MT|ARM64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release-Hotplug-MT|Win32.ActiveCfg = Release-Hotplug-MT|Win32
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release-Hotplug-MT|Win32.Build.0 = Release-Hotplug-MT|Win32
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release-Hotplug-MT|x64.ActiveCfg = Release-Hotplug-MT|x64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release-Hotplug-MT|x64.Build.0 = Release-Hotplug-MT|x64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release-MT|ARM64.ActiveCfg = Release-MT|ARM64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release-MT|ARM64.Build.0 = Release-MT|ARM64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release-MT|Win32.ActiveCfg = Release-MT|Win32
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release-MT|Win32.Build.0 = Release-MT|Win32
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release-MT|x64.ActiveCfg = Release-MT|x64
{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release-MT|x64.Build.0 = Release-MT|x64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug|ARM64.ActiveCfg = Debug|ARM64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug|ARM64.Build.0 = Debug|ARM64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug|Win32.ActiveCfg = Debug|Win32
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug|Win32.Build.0 = Debug|Win32
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug|x64.ActiveCfg = Debug|x64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug|x64.Build.0 = Debug|x64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug-Hotplug|ARM64.ActiveCfg = Debug-Hotplug|ARM64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug-Hotplug|ARM64.Build.0 = Debug-Hotplug|ARM64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug-Hotplug|Win32.ActiveCfg = Debug-Hotplug|Win32
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug-Hotplug|Win32.Build.0 = Debug-Hotplug|Win32
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug-Hotplug|x64.ActiveCfg = Debug-Hotplug|x64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug-Hotplug|x64.Build.0 = Debug-Hotplug|x64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug-Hotplug-MT|ARM64.ActiveCfg = Debug-Hotplug-MT|ARM64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug-Hotplug-MT|ARM64.Build.0 = Debug-Hotplug-MT|ARM64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug-Hotplug-MT|Win32.ActiveCfg = Debug-Hotplug-MT|Win32
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug-Hotplug-MT|Win32.Build.0 = Debug-Hotplug-MT|Win32
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug-Hotplug-MT|x64.ActiveCfg = Debug-Hotplug-MT|x64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug-Hotplug-MT|x64.Build.0 = Debug-Hotplug-MT|x64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug-MT|ARM64.ActiveCfg = Debug-MT|ARM64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug-MT|ARM64.Build.0 = Debug-MT|ARM64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug-MT|Win32.ActiveCfg = Debug-MT|Win32
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug-MT|Win32.Build.0 = Debug-MT|Win32
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug-MT|x64.ActiveCfg = Debug-MT|x64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Debug-MT|x64.Build.0 = Debug-MT|x64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release|ARM64.ActiveCfg = Release|ARM64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release|ARM64.Build.0 = Release|ARM64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release|Win32.ActiveCfg = Release|Win32
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release|Win32.Build.0 = Release|Win32
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release|x64.ActiveCfg = Release|x64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release|x64.Build.0 = Release|x64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release-Hotplug|ARM64.ActiveCfg = Release-Hotplug|ARM64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release-Hotplug|ARM64.Build.0 = Release-Hotplug|ARM64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release-Hotplug|Win32.ActiveCfg = Release-Hotplug|Win32
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release-Hotplug|Win32.Build.0 = Release-Hotplug|Win32
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release-Hotplug|x64.ActiveCfg = Release-Hotplug|x64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release-Hotplug|x64.Build.0 = Release-Hotplug|x64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release-Hotplug-MT|ARM64.ActiveCfg = Release-Hotplug-MT|ARM64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release-Hotplug-MT|ARM64.Build.0 = Release-Hotplug-MT|ARM64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release-Hotplug-MT|Win32.ActiveCfg = Release-Hotplug-MT|Win32
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release-Hotplug-MT|Win32.Build.0 = Release-Hotplug-MT|Win32
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release-Hotplug-MT|x64.ActiveCfg = Release-Hotplug-MT|x64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release-Hotplug-MT|x64.Build.0 = Release-Hotplug-MT|x64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release-MT|ARM64.ActiveCfg = Release-MT|ARM64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release-MT|ARM64.Build.0 = Release-MT|ARM64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release-MT|Win32.ActiveCfg = Release-MT|Win32
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release-MT|Win32.Build.0 = Release-MT|Win32
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release-MT|x64.ActiveCfg = Release-MT|x64
{99D2AC64-DC66-4422-91CE-6715C403C9E5}.Release-MT|x64.Build.0 = Release-MT|x64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Debug|ARM64.ActiveCfg = Debug|ARM64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Debug|ARM64.Build.0 = Debug|ARM64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Debug|Win32.ActiveCfg = Debug|Win32
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Debug|Win32.Build.0 = Debug|Win32
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Debug|x64.ActiveCfg = Debug|x64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Debug|x64.Build.0 = Debug|x64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Debug-Hotplug|ARM64.ActiveCfg = Debug-Hotplug|ARM64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Debug-Hotplug|ARM64.Build.0 = Debug-Hotplug|ARM64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Debug-Hotplug|Win32.ActiveCfg = Debug-Hotplug|Win32
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Debug-Hotplug|Win32.Build.0 = Debug-Hotplug|Win32
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Debug-Hotplug|x64.ActiveCfg = Debug-Hotplug|x64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Debug-Hotplug|x64.Build.0 = Debug-Hotplug|x64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Debug-Hotplug-MT|ARM64.ActiveCfg = Debug-Hotplug-MT|ARM64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Debug-Hotplug-MT|ARM64.Build.0 = Debug-Hotplug-MT|ARM64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Debug-Hotplug-MT|Win32.ActiveCfg = Debug-Hotplug-MT|Win32
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Debug-Hotplug-MT|Win32.Build.0 = Debug-Hotplug-MT|Win32
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Debug-Hotplug-MT|x64.ActiveCfg = Debug-Hotplug-MT|x64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Debug-Hotplug-MT|x64.Build.0 = Debug-Hotplug-MT|x64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Debug-MT|ARM64.ActiveCfg = Debug-MT|ARM64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Debug-MT|ARM64.Build.0 = Debug-MT|ARM64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Debug-MT|Win32.ActiveCfg = Debug-MT|Win32
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Debug-MT|Win32.Build.0 = Debug-MT|Win32
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Debug-MT|x64.ActiveCfg = Debug-MT|x64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Debug-MT|x64.Build.0 = Debug-MT|x64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Release|ARM64.ActiveCfg = Release|ARM64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Release|ARM64.Build.0 = Release|ARM64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Release|Win32.ActiveCfg = Release|Win32
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Release|Win32.Build.0 = Release|Win32
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Release|x64.ActiveCfg = Release|x64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Release|x64.Build.0 = Release|x64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Release-Hotplug|ARM64.ActiveCfg = Release-Hotplug|ARM64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Release-Hotplug|ARM64.Build.0 = Release-Hotplug|ARM64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Release-Hotplug|Win32.ActiveCfg = Release-Hotplug|Win32
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Release-Hotplug|Win32.Build.0 = Release-Hotplug|Win32
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Release-Hotplug|x64.ActiveCfg = Release-Hotplug|x64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Release-Hotplug|x64.Build.0 = Release-Hotplug|x64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Release-Hotplug-MT|ARM64.ActiveCfg = Release-Hotplug-MT|ARM64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Release-Hotplug-MT|ARM64.Build.0 = Release-Hotplug-MT|ARM64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Release-Hotplug-MT|Win32.ActiveCfg = Release-Hotplug-MT|Win32
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Release-Hotplug-MT|Win32.Build.0 = Release-Hotplug-MT|Win32
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Release-Hotplug-MT|x64.ActiveCfg = Release-Hotplug-MT|x64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Release-Hotplug-MT|x64.Build.0 = Release-Hotplug-MT|x64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Release-MT|ARM64.ActiveCfg = Release-MT|ARM64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Release-MT|ARM64.Build.0 = Release-MT|ARM64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Release-MT|Win32.ActiveCfg = Release-MT|Win32
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Release-MT|Win32.Build.0 = Release-MT|Win32
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Release-MT|x64.ActiveCfg = Release-MT|x64
{FB388436-7D25-4A7E-BD3C-DF4EE9FCC8F7}.Release-MT|x64.Build.0 = Release-MT|x64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug|ARM64.ActiveCfg = Debug|ARM64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug|ARM64.Build.0 = Debug|ARM64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug|Win32.ActiveCfg = Debug|Win32
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug|Win32.Build.0 = Debug|Win32
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug|x64.ActiveCfg = Debug|x64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug|x64.Build.0 = Debug|x64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug-Hotplug|ARM64.ActiveCfg = Debug-Hotplug|ARM64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug-Hotplug|ARM64.Build.0 = Debug-Hotplug|ARM64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug-Hotplug|Win32.ActiveCfg = Debug-Hotplug|Win32
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug-Hotplug|Win32.Build.0 = Debug-Hotplug|Win32
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug-Hotplug|x64.ActiveCfg = Debug-Hotplug|x64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug-Hotplug|x64.Build.0 = Debug-Hotplug|x64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug-Hotplug-MT|ARM64.ActiveCfg = Debug-Hotplug-MT|ARM64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug-Hotplug-MT|ARM64.Build.0 = Debug-Hotplug-MT|ARM64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug-Hotplug-MT|Win32.ActiveCfg = Debug-Hotplug-MT|Win32
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug-Hotplug-MT|Win32.Build.0 = Debug-Hotplug-MT|Win32
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug-Hotplug-MT|x64.ActiveCfg = Debug-Hotplug-MT|x64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug-Hotplug-MT|x64.Build.0 = Debug-Hotplug-MT|x64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug-MT|ARM64.ActiveCfg = Debug-MT|ARM64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug-MT|ARM64.Build.0 = Debug-MT|ARM64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug-MT|Win32.ActiveCfg = Debug-MT|Win32
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug-MT|Win32.Build.0 = Debug-MT|Win32
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug-MT|x64.ActiveCfg = Debug-MT|x64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug-MT|x64.Build.0 = Debug-MT|x64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release|ARM64.ActiveCfg = Release|ARM64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release|ARM64.Build.0 = Release|ARM64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release|Win32.ActiveCfg = Release|Win32
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release|Win32.Build.0 = Release|Win32
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release|x64.ActiveCfg = Release|x64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release|x64.Build.0 = Release|x64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release-Hotplug|ARM64.ActiveCfg = Release-Hotplug|ARM64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release-Hotplug|ARM64.Build.0 = Release-Hotplug|ARM64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release-Hotplug|Win32.ActiveCfg = Release-Hotplug|Win32
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release-Hotplug|Win32.Build.0 = Release-Hotplug|Win32
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release-Hotplug|x64.ActiveCfg = Release-Hotplug|x64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release-Hotplug|x64.Build.0 = Release-Hotplug|x64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release-Hotplug-MT|ARM64.ActiveCfg = Release-Hotplug-MT|ARM64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release-Hotplug-MT|ARM64.Build.0 = Release-Hotplug-MT|ARM64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release-Hotplug-MT|Win32.ActiveCfg = Release-Hotplug-MT|Win32
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release-Hotplug-MT|Win32.Build.0 = Release-Hotplug-MT|Win32
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release-Hotplug-MT|x64.ActiveCfg = Release-Hotplug-MT|x64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release-Hotplug-MT|x64.Build.0 = Release-Hotplug-MT|x64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release-MT|ARM64.ActiveCfg = Release-MT|ARM64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release-MT|ARM64.Build.0 = Release-MT|ARM64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release-MT|Win32.ActiveCfg = Release-MT|Win32
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release-MT|Win32.Build.0 = Release-MT|Win32
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release-MT|x64.ActiveCfg = Release-MT|x64
{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release-MT|x64.Build.0 = Release-MT|x64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|ARM64.ActiveCfg = Debug|ARM64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|ARM64.Build.0 = Debug|ARM64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|Win32.ActiveCfg = Debug|Win32
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|Win32.Build.0 = Debug|Win32
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|x64.ActiveCfg = Debug|x64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug|x64.Build.0 = Debug|x64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug-Hotplug|ARM64.ActiveCfg = Debug-Hotplug|ARM64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug-Hotplug|ARM64.Build.0 = Debug-Hotplug|ARM64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug-Hotplug|Win32.ActiveCfg = Debug-Hotplug|Win32
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug-Hotplug|Win32.Build.0 = Debug-Hotplug|Win32
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug-Hotplug|x64.ActiveCfg = Debug-Hotplug|x64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug-Hotplug|x64.Build.0 = Debug-Hotplug|x64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug-Hotplug-MT|ARM64.ActiveCfg = Debug-Hotplug-MT|ARM64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug-Hotplug-MT|ARM64.Build.0 = Debug-Hotplug-MT|ARM64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug-Hotplug-MT|Win32.ActiveCfg = Debug-Hotplug-MT|Win32
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug-Hotplug-MT|Win32.Build.0 = Debug-Hotplug-MT|Win32
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug-Hotplug-MT|x64.ActiveCfg = Debug-Hotplug-MT|x64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug-Hotplug-MT|x64.Build.0 = Debug-Hotplug-MT|x64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug-MT|ARM64.ActiveCfg = Debug-MT|ARM64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug-MT|ARM64.Build.0 = Debug-MT|ARM64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug-MT|Win32.ActiveCfg = Debug-MT|Win32
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug-MT|Win32.Build.0 = Debug-MT|Win32
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug-MT|x64.ActiveCfg = Debug-MT|x64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Debug-MT|x64.Build.0 = Debug-MT|x64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|ARM64.ActiveCfg = Release|ARM64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|ARM64.Build.0 = Release|ARM64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|Win32.ActiveCfg = Release|Win32
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|Win32.Build.0 = Release|Win32
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|x64.ActiveCfg = Release|x64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release|x64.Build.0 = Release|x64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release-Hotplug|ARM64.ActiveCfg = Release-Hotplug|ARM64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release-Hotplug|ARM64.Build.0 = Release-Hotplug|ARM64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release-Hotplug|Win32.ActiveCfg = Release-Hotplug|Win32
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release-Hotplug|Win32.Build.0 = Release-Hotplug|Win32
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release-Hotplug|x64.ActiveCfg = Release-Hotplug|x64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release-Hotplug|x64.Build.0 = Release-Hotplug|x64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release-Hotplug-MT|ARM64.ActiveCfg = Release-Hotplug-MT|ARM64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release-Hotplug-MT|ARM64.Build.0 = Release-Hotplug-MT|ARM64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release-Hotplug-MT|Win32.ActiveCfg = Release-Hotplug-MT|Win32
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release-Hotplug-MT|Win32.Build.0 = Release-Hotplug-MT|Win32
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release-Hotplug-MT|x64.ActiveCfg = Release-Hotplug-MT|x64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release-Hotplug-MT|x64.Build.0 = Release-Hotplug-MT|x64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release-MT|ARM64.ActiveCfg = Release-MT|ARM64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release-MT|ARM64.Build.0 = Release-MT|ARM64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release-MT|Win32.ActiveCfg = Release-MT|Win32
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release-MT|Win32.Build.0 = Release-MT|Win32
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release-MT|x64.ActiveCfg = Release-MT|x64
{861CDD5F-59A2-4F34-957E-5C1AF98BE0A4}.Release-MT|x64.Build.0 = Release-MT|x64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug|ARM64.ActiveCfg = Debug|ARM64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug|ARM64.Build.0 = Debug|ARM64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug|Win32.ActiveCfg = Debug|Win32
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug|Win32.Build.0 = Debug|Win32
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug|x64.ActiveCfg = Debug|x64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug|x64.Build.0 = Debug|x64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug-Hotplug|ARM64.ActiveCfg = Debug-Hotplug|ARM64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug-Hotplug|ARM64.Build.0 = Debug-Hotplug|ARM64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug-Hotplug|Win32.ActiveCfg = Debug-Hotplug|Win32
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug-Hotplug|Win32.Build.0 = Debug-Hotplug|Win32
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug-Hotplug|x64.ActiveCfg = Debug-Hotplug|x64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug-Hotplug|x64.Build.0 = Debug-Hotplug|x64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug-Hotplug-MT|ARM64.ActiveCfg = Debug-Hotplug-MT|ARM64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug-Hotplug-MT|ARM64.Build.0 = Debug-Hotplug-MT|ARM64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug-Hotplug-MT|Win32.ActiveCfg = Debug-Hotplug-MT|Win32
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug-Hotplug-MT|Win32.Build.0 = Debug-Hotplug-MT|Win32
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug-Hotplug-MT|x64.ActiveCfg = Debug-Hotplug-MT|x64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug-Hotplug-MT|x64.Build.0 = Debug-Hotplug-MT|x64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug-MT|ARM64.ActiveCfg = Debug-MT|ARM64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug-MT|ARM64.Build.0 = Debug-MT|ARM64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug-MT|Win32.ActiveCfg = Debug-MT|Win32
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug-MT|Win32.Build.0 = Debug-MT|Win32
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug-MT|x64.ActiveCfg = Debug-MT|x64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Debug-MT|x64.Build.0 = Debug-MT|x64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release|ARM64.ActiveCfg = Release|ARM64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release|ARM64.Build.0 = Release|ARM64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release|Win32.ActiveCfg = Release|Win32
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release|Win32.Build.0 = Release|Win32
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release|x64.ActiveCfg = Release|x64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release|x64.Build.0 = Release|x64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release-Hotplug|ARM64.ActiveCfg = Release-Hotplug|ARM64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release-Hotplug|ARM64.Build.0 = Release-Hotplug|ARM64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release-Hotplug|Win32.ActiveCfg = Release-Hotplug|Win32
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release-Hotplug|Win32.Build.0 = Release-Hotplug|Win32
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release-Hotplug|x64.ActiveCfg = Release-Hotplug|x64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release-Hotplug|x64.Build.0 = Release-Hotplug|x64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release-Hotplug-MT|ARM64.ActiveCfg = Release-Hotplug-MT|ARM64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release-Hotplug-MT|ARM64.Build.0 = Release-Hotplug-MT|ARM64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release-Hotplug-MT|Win32.ActiveCfg = Release-Hotplug-MT|Win32
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release-Hotplug-MT|Win32.Build.0 = Release-Hotplug-MT|Win32
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release-Hotplug-MT|x64.ActiveCfg = Release-Hotplug-MT|x64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release-Hotplug-MT|x64.Build.0 = Release-Hotplug-MT|x64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release-MT|ARM64.ActiveCfg = Release-MT|ARM64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release-MT|ARM64.Build.0 = Release-MT|ARM64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release-MT|Win32.ActiveCfg = Release-MT|Win32
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release-MT|Win32.Build.0 = Release-MT|Win32
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release-MT|x64.ActiveCfg = Release-MT|x64
{53942EFF-C810-458D-B3CB-EE5CE9F1E781}.Release-MT|x64.Build.0 = Release-MT|x64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Debug|ARM64.ActiveCfg = Debug|ARM64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Debug|ARM64.Build.0 = Debug|ARM64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Debug|Win32.ActiveCfg = Debug|Win32
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Debug|Win32.Build.0 = Debug|Win32
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Debug|x64.ActiveCfg = Debug|x64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Debug|x64.Build.0 = Debug|x64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Debug-Hotplug|ARM64.ActiveCfg = Debug-Hotplug|ARM64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Debug-Hotplug|ARM64.Build.0 = Debug-Hotplug|ARM64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Debug-Hotplug|Win32.ActiveCfg = Debug-Hotplug|Win32
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Debug-Hotplug|Win32.Build.0 = Debug-Hotplug|Win32
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Debug-Hotplug|x64.ActiveCfg = Debug-Hotplug|x64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Debug-Hotplug|x64.Build.0 = Debug-Hotplug|x64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Debug-Hotplug-MT|ARM64.ActiveCfg = Debug-Hotplug-MT|ARM64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Debug-Hotplug-MT|ARM64.Build.0 = Debug-Hotplug-MT|ARM64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Debug-Hotplug-MT|Win32.ActiveCfg = Debug-Hotplug-MT|Win32
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Debug-Hotplug-MT|Win32.Build.0 = Debug-Hotplug-MT|Win32
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Debug-Hotplug-MT|x64.ActiveCfg = Debug-Hotplug-MT|x64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Debug-Hotplug-MT|x64.Build.0 = Debug-Hotplug-MT|x64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Debug-MT|ARM64.ActiveCfg = Debug-MT|ARM64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Debug-MT|ARM64.Build.0 = Debug-MT|ARM64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Debug-MT|Win32.ActiveCfg = Debug-MT|Win32
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Debug-MT|Win32.Build.0 = Debug-MT|Win32
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Debug-MT|x64.ActiveCfg = Debug-MT|x64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Debug-MT|x64.Build.0 = Debug-MT|x64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Release|ARM64.ActiveCfg = Release|ARM64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Release|ARM64.Build.0 = Release|ARM64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Release|Win32.ActiveCfg = Release|Win32
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Release|Win32.Build.0 = Release|Win32
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Release|x64.ActiveCfg = Release|x64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Release|x64.Build.0 = Release|x64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Release-Hotplug|ARM64.ActiveCfg = Release-Hotplug|ARM64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Release-Hotplug|ARM64.Build.0 = Release-Hotplug|ARM64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Release-Hotplug|Win32.ActiveCfg = Release-Hotplug|Win32
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Release-Hotplug|Win32.Build.0 = Release-Hotplug|Win32
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Release-Hotplug|x64.ActiveCfg = Release-Hotplug|x64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Release-Hotplug|x64.Build.0 = Release-Hotplug|x64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Release-Hotplug-MT|ARM64.ActiveCfg = Release-Hotplug-MT|ARM64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Release-Hotplug-MT|ARM64.Build.0 = Release-Hotplug-MT|ARM64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Release-Hotplug-MT|Win32.ActiveCfg = Release-Hotplug-MT|Win32
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Release-Hotplug-MT|Win32.Build.0 = Release-Hotplug-MT|Win32
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Release-Hotplug-MT|x64.ActiveCfg = Release-Hotplug-MT|x64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Release-Hotplug-MT|x64.Build.0 = Release-Hotplug-MT|x64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Release-MT|ARM64.ActiveCfg = Release-MT|ARM64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Release-MT|ARM64.Build.0 = Release-MT|ARM64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Release-MT|Win32.ActiveCfg = Release-MT|Win32
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Release-MT|Win32.Build.0 = Release-MT|Win32
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Release-MT|x64.ActiveCfg = Release-MT|x64
{9EAF1311-2BBB-4177-882B-DA7FA0AD7912}.Release-MT|x64.Build.0 = Release-MT|x64
{70828935-325B-4749-B381-0E55EF31AEE8}.Debug|ARM64.ActiveCfg = Debug|ARM64
{70828935-325B-4749-B381-0E55EF31AEE8}.Debug|ARM64.Build.0 = Debug|ARM64
{70828935-325B-4749-B381-0E55EF31AEE8}.Debug|Win32.ActiveCfg = Debug|Win32
{70828935-325B-4749-B381-0E55EF31AEE8}.Debug|Win32.Build.0 = Debug|Win32
{70828935-325B-4749-B381-0E55EF31AEE8}.Debug|x64.ActiveCfg = Debug|x64
{70828935-325B-4749-B381-0E55EF31AEE8}.Debug|x64.Build.0 = Debug|x64
{70828935-325B-4749-B381-0E55EF31AEE8}.Debug-Hotplug|ARM64.ActiveCfg = Debug-Hotplug|ARM64
{70828935-325B-4749-B381-0E55EF31AEE8}.Debug-Hotplug|ARM64.Build.0 = Debug-Hotplug|ARM64
{70828935-325B-4749-B381-0E55EF31AEE8}.Debug-Hotplug|Win32.ActiveCfg = Debug-Hotplug|Win32
{70828935-325B-4749-B381-0E55EF31AEE8}.Debug-Hotplug|Win32.Build.0 = Debug-Hotplug|Win32
{70828935-325B-4749-B381-0E55EF31AEE8}.Debug-Hotplug|x64.ActiveCfg = Debug-Hotplug|x64
{70828935-325B-4749-B381-0E55EF31AEE8}.Debug-Hotplug|x64.Build.0 = Debug-Hotplug|x64
{70828935-325B-4749-B381-0E55EF31AEE8}.Debug-Hotplug-MT|ARM64.ActiveCfg = Debug-Hotplug-MT|ARM64
{70828935-325B-4749-B381-0E55EF31AEE8}.Debug-Hotplug-MT|ARM64.Build.0 = Debug-Hotplug-MT|ARM64
{70828935-325B-4749-B381-0E55EF31AEE8}.Debug-Hotplug-MT|Win32.ActiveCfg = Debug-Hotplug-MT|Win32
{70828935-325B-4749-B381-0E55EF31AEE8}.Debug-Hotplug-MT|Win32.Build.0 = Debug-Hotplug-MT|Win32
{70828935-325B-4749-B381-0E55EF31AEE8}.Debug-Hotplug-MT|x64.ActiveCfg = Debug-Hotplug-MT|x64
{70828935-325B-4749-B381-0E55EF31AEE8}.Debug-Hotplug-MT|x64.Build.0 = Debug-Hotplug-MT|x64
{70828935-325B-4749-B381-0E55EF31AEE8}.Debug-MT|ARM64.ActiveCfg = Debug-MT|ARM64
{70828935-325B-4749-B381-0E55EF31AEE8}.Debug-MT|ARM64.Build.0 = Debug-MT|ARM64
{70828935-325B-4749-B381-0E55EF31AEE8}.Debug-MT|Win32.ActiveCfg = Debug-MT|Win32
{70828935-325B-4749-B381-0E55EF31AEE8}.Debug-MT|Win32.Build.0 = Debug-MT|Win32
{70828935-325B-4749-B381-0E55EF31AEE8}.Debug-MT|x64.ActiveCfg = Debug-MT|x64
{70828935-325B-4749-B381-0E55EF31AEE8}.Debug-MT|x64.Build.0 = Debug-MT|x64
{70828935-325B-4749-B381-0E55EF31AEE8}.Release|ARM64.ActiveCfg = Release|ARM64
{70828935-325B-4749-B381-0E55EF31AEE8}.Release|ARM64.Build.0 = Release|ARM64
{70828935-325B-4749-B381-0E55EF31AEE8}.Release|Win32.ActiveCfg = Release|Win32
{70828935-325B-4749-B381-0E55EF31AEE8}.Release|Win32.Build.0 = Release|Win32
{70828935-325B-4749-B381-0E55EF31AEE8}.Release|x64.ActiveCfg = Release|x64
{70828935-325B-4749-B381-0E55EF31AEE8}.Release|x64.Build.0 = Release|x64
{70828935-325B-4749-B381-0E55EF31AEE8}.Release-Hotplug|ARM64.ActiveCfg = Release-Hotplug|ARM64
{70828935-325B-4749-B381-0E55EF31AEE8}.Release-Hotplug|ARM64.Build.0 = Release-Hotplug|ARM64
{70828935-325B-4749-B381-0E55EF31AEE8}.Release-Hotplug|Win32.ActiveCfg = Release-Hotplug|Win32
{70828935-325B-4749-B381-0E55EF31AEE8}.Release-Hotplug|Win32.Build.0 = Release-Hotplug|Win32
{70828935-325B-4749-B381-0E55EF31AEE8}.Release-Hotplug|x64.ActiveCfg = Release-Hotplug|x64
{70828935-325B-4749-B381-0E55EF31AEE8}.Release-Hotplug|x64.Build.0 = Release-Hotplug|x64
{70828935-325B-4749-B381-0E55EF31AEE8}.Release-Hotplug-MT|ARM64.ActiveCfg = Release-Hotplug-MT|ARM64
{70828935-325B-4749-B381-0E55EF31AEE8}.Release-Hotplug-MT|ARM64.Build.0 = Release-Hotplug-MT|ARM64
{70828935-325B-4749-B381-0E55EF31AEE8}.Release-Hotplug-MT|Win32.ActiveCfg = Release-Hotplug-MT|Win32
{70828935-325B-4749-B381-0E55EF31AEE8}.Release-Hotplug-MT|Win32.Build.0 = Release-Hotplug-MT|Win32
{70828935-325B-4749-B381-0E55EF31AEE8}.Release-Hotplug-MT|x64.ActiveCfg = Release-Hotplug-MT|x64
{70828935-325B-4749-B381-0E55EF31AEE8}.Release-Hotplug-MT|x64.Build.0 = Release-Hotplug-MT|x64
{70828935-325B-4749-B381-0E55EF31AEE8}.Release-MT|ARM64.ActiveCfg = Release-MT|ARM64
{70828935-325B-4749-B381-0E55EF31AEE8}.Release-MT|ARM64.Build.0 = Release-MT|ARM64
{70828935-325B-4749-B381-0E55EF31AEE8}.Release-MT|Win32.ActiveCfg = Release-MT|Win32
{70828935-325B-4749-B381-0E55EF31AEE8}.Release-MT|Win32.Build.0 = Release-MT|Win32
{70828935-325B-4749-B381-0E55EF31AEE8}.Release-MT|x64.ActiveCfg = Release-MT|x64
{70828935-325B-4749-B381-0E55EF31AEE8}.Release-MT|x64.Build.0 = Release-MT|x64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug|ARM64.ActiveCfg = Debug|ARM64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug|ARM64.Build.0 = Debug|ARM64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug|Win32.ActiveCfg = Debug|Win32
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug|Win32.Build.0 = Debug|Win32
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug|x64.ActiveCfg = Debug|x64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug|x64.Build.0 = Debug|x64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug-Hotplug|ARM64.ActiveCfg = Debug-Hotplug|ARM64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug-Hotplug|ARM64.Build.0 = Debug-Hotplug|ARM64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug-Hotplug|Win32.ActiveCfg = Debug-Hotplug|Win32
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug-Hotplug|Win32.Build.0 = Debug-Hotplug|Win32
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug-Hotplug|x64.ActiveCfg = Debug-Hotplug|x64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug-Hotplug|x64.Build.0 = Debug-Hotplug|x64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug-Hotplug-MT|ARM64.ActiveCfg = Debug-Hotplug-MT|ARM64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug-Hotplug-MT|ARM64.Build.0 = Debug-Hotplug-MT|ARM64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug-Hotplug-MT|Win32.ActiveCfg = Debug-Hotplug-MT|Win32
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug-Hotplug-MT|Win32.Build.0 = Debug-Hotplug-MT|Win32
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug-Hotplug-MT|x64.ActiveCfg = Debug-Hotplug-MT|x64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug-Hotplug-MT|x64.Build.0 = Debug-Hotplug-MT|x64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug-MT|ARM64.ActiveCfg = Debug-MT|ARM64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug-MT|ARM64.Build.0 = Debug-MT|ARM64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug-MT|Win32.ActiveCfg = Debug-MT|Win32
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug-MT|Win32.Build.0 = Debug-MT|Win32
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug-MT|x64.ActiveCfg = Debug-MT|x64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug-MT|x64.Build.0 = Debug-MT|x64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release|ARM64.ActiveCfg = Release|ARM64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release|ARM64.Build.0 = Release|ARM64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release|Win32.ActiveCfg = Release|Win32
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release|Win32.Build.0 = Release|Win32
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release|x64.ActiveCfg = Release|x64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release|x64.Build.0 = Release|x64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release-Hotplug|ARM64.ActiveCfg = Release-Hotplug|ARM64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release-Hotplug|ARM64.Build.0 = Release-Hotplug|ARM64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release-Hotplug|Win32.ActiveCfg = Release-Hotplug|Win32
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release-Hotplug|Win32.Build.0 = Release-Hotplug|Win32
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release-Hotplug|x64.ActiveCfg = Release-Hotplug|x64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release-Hotplug|x64.Build.0 = Release-Hotplug|x64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release-Hotplug-MT|ARM64.ActiveCfg = Release-Hotplug-MT|ARM64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release-Hotplug-MT|ARM64.Build.0 = Release-Hotplug-MT|ARM64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release-Hotplug-MT|Win32.ActiveCfg = Release-Hotplug-MT|Win32
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release-Hotplug-MT|Win32.Build.0 = Release-Hotplug-MT|Win32
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release-Hotplug-MT|x64.ActiveCfg = Release-Hotplug-MT|x64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release-Hotplug-MT|x64.Build.0 = Release-Hotplug-MT|x64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release-MT|ARM64.ActiveCfg = Release-MT|ARM64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release-MT|ARM64.Build.0 = Release-MT|ARM64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release-MT|Win32.ActiveCfg = Release-MT|Win32
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release-MT|Win32.Build.0 = Release-MT|Win32
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release-MT|x64.ActiveCfg = Release-MT|x64
{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release-MT|x64.Build.0 = Release-MT|x64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Debug|ARM64.ActiveCfg = Debug|ARM64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Debug|ARM64.Build.0 = Debug|ARM64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Debug|Win32.ActiveCfg = Debug|Win32
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Debug|Win32.Build.0 = Debug|Win32
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Debug|x64.ActiveCfg = Debug|x64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Debug|x64.Build.0 = Debug|x64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Debug-Hotplug|ARM64.ActiveCfg = Debug-Hotplug|ARM64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Debug-Hotplug|ARM64.Build.0 = Debug-Hotplug|ARM64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Debug-Hotplug|Win32.ActiveCfg = Debug-Hotplug|Win32
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Debug-Hotplug|Win32.Build.0 = Debug-Hotplug|Win32
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Debug-Hotplug|x64.ActiveCfg = Debug-Hotplug|x64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Debug-Hotplug|x64.Build.0 = Debug-Hotplug|x64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Debug-Hotplug-MT|ARM64.ActiveCfg = Debug-Hotplug-MT|ARM64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Debug-Hotplug-MT|ARM64.Build.0 = Debug-Hotplug-MT|ARM64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Debug-Hotplug-MT|Win32.ActiveCfg = Debug-Hotplug-MT|Win32
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Debug-Hotplug-MT|Win32.Build.0 = Debug-Hotplug-MT|Win32
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Debug-Hotplug-MT|x64.ActiveCfg = Debug-Hotplug-MT|x64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Debug-Hotplug-MT|x64.Build.0 = Debug-Hotplug-MT|x64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Debug-MT|ARM64.ActiveCfg = Debug-MT|ARM64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Debug-MT|ARM64.Build.0 = Debug-MT|ARM64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Debug-MT|Win32.ActiveCfg = Debug-MT|Win32
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Debug-MT|Win32.Build.0 = Debug-MT|Win32
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Debug-MT|x64.ActiveCfg = Debug-MT|x64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Debug-MT|x64.Build.0 = Debug-MT|x64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Release|ARM64.ActiveCfg = Release|ARM64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Release|ARM64.Build.0 = Release|ARM64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Release|Win32.ActiveCfg = Release|Win32
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Release|Win32.Build.0 = Release|Win32
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Release|x64.ActiveCfg = Release|x64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Release|x64.Build.0 = Release|x64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Release-Hotplug|ARM64.ActiveCfg = Release-Hotplug|ARM64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Release-Hotplug|ARM64.Build.0 = Release-Hotplug|ARM64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Release-Hotplug|Win32.ActiveCfg = Release-Hotplug|Win32
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Release-Hotplug|Win32.Build.0 = Release-Hotplug|Win32
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Release-Hotplug|x64.ActiveCfg = Release-Hotplug|x64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Release-Hotplug|x64.Build.0 = Release-Hotplug|x64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Release-Hotplug-MT|ARM64.ActiveCfg = Release-Hotplug-MT|ARM64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Release-Hotplug-MT|ARM64.Build.0 = Release-Hotplug-MT|ARM64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Release-Hotplug-MT|Win32.ActiveCfg = Release-Hotplug-MT|Win32
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Release-Hotplug-MT|Win32.Build.0 = Release-Hotplug-MT|Win32
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Release-Hotplug-MT|x64.ActiveCfg = Release-Hotplug-MT|x64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Release-Hotplug-MT|x64.Build.0 = Release-Hotplug-MT|x64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Release-MT|ARM64.ActiveCfg = Release-MT|ARM64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Release-MT|ARM64.Build.0 = Release-MT|ARM64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Release-MT|Win32.ActiveCfg = Release-MT|Win32
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Release-MT|Win32.Build.0 = Release-MT|Win32
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Release-MT|x64.ActiveCfg = Release-MT|x64
{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}.Release-MT|x64.Build.0 = Release-MT|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AD8203A3-88DD-4212-A273-100DFAD69F6B}
EndGlobalSection
EndGlobal
@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="ProjectConfigurations.Base.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{349EE8FA-7D25-4909-AAF5-FF3FADE72187}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="Configuration.DynamicLibrary.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="Base.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<OutDir>$(IntDir)..\dll\</OutDir>
<TargetName>libusb-1.0</TargetName>
</PropertyGroup>
<ItemDefinitionGroup>
<Link>
<EmbedManagedResourceFile>libusb-1.0.rc;%(EmbedManagedResourceFile)</EmbedManagedResourceFile>
<ModuleDefinitionFile>..\libusb\libusb-1.0.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\libusb\core.c" />
<ClCompile Include="..\libusb\descriptor.c" />
<ClCompile Include="..\libusb\os\events_windows.c" />
<ClCompile Include="..\libusb\hotplug.c" />
<ClCompile Include="..\libusb\io.c" />
<ClCompile Condition="'$(EnableWindowsHotplug)' == 'true'" Include="..\libusb\os\windows_hotplug.c" />
<ClCompile Include="..\libusb\strerror.c" />
<ClCompile Include="..\libusb\sync.c" />
<ClCompile Include="..\libusb\os\threads_windows.c" />
<ClCompile Include="..\libusb\os\windows_common.c" />
<ClCompile Include="..\libusb\os\windows_usbdk.c" />
<ClCompile Include="..\libusb\os\windows_winusb.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Condition="'$(EnableWindowsHotplug)' == 'true'" Include="..\libusb\os\windows_hotplug.h" />
<ClInclude Include=".\config.h" />
<ClInclude Include="..\libusb\os\events_windows.h" />
<ClInclude Include="..\libusb\libusb.h" />
<ClInclude Include="..\libusb\libusbi.h" />
<ClInclude Include="..\libusb\os\threads_windows.h" />
<ClInclude Include="..\libusb\version.h" />
<ClInclude Include="..\libusb\version_nano.h" />
<ClInclude Include="..\libusb\os\windows_common.h" />
<ClInclude Include="..\libusb\os\windows_usbdk.h" />
<ClInclude Include="..\libusb\os\windows_winusb.h" />
</ItemGroup>
<ItemGroup>
<None Include="..\libusb\libusb-1.0.def" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\libusb\libusb-1.0.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="ProjectConfigurations.Base.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{349EE8F9-7D25-4909-AAF5-FF3FADE72187}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="Configuration.StaticLibrary.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="Base.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<OutDir>$(IntDir)..\lib\</OutDir>
<TargetName>libusb-1.0</TargetName>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\libusb\core.c" />
<ClCompile Include="..\libusb\descriptor.c" />
<ClCompile Include="..\libusb\os\events_windows.c" />
<ClCompile Include="..\libusb\hotplug.c" />
<ClCompile Include="..\libusb\io.c" />
<ClCompile Condition="'$(EnableWindowsHotplug)' == 'true'" Include="..\libusb\os\windows_hotplug.c" />
<ClCompile Include="..\libusb\strerror.c" />
<ClCompile Include="..\libusb\sync.c" />
<ClCompile Include="..\libusb\os\threads_windows.c" />
<ClCompile Include="..\libusb\os\windows_common.c" />
<ClCompile Include="..\libusb\os\windows_usbdk.c" />
<ClCompile Include="..\libusb\os\windows_winusb.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Condition="'$(EnableWindowsHotplug)' == 'true'" Include="..\libusb\os\windows_hotplug.h" />
<ClInclude Include=".\config.h" />
<ClInclude Include="..\libusb\os\events_windows.h" />
<ClInclude Include="..\libusb\libusb.h" />
<ClInclude Include="..\libusb\libusbi.h" />
<ClInclude Include="..\libusb\os\threads_windows.h" />
<ClInclude Include="..\libusb\version.h" />
<ClInclude Include="..\libusb\version_nano.h" />
<ClInclude Include="..\libusb\os\windows_common.h" />
<ClInclude Include="..\libusb\os\windows_usbdk.h" />
<ClInclude Include="..\libusb\os\windows_winusb.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="ProjectConfigurations.Base.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="Configuration.Application.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="Base.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemGroup>
<ClCompile Include="..\examples\listdevs.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\libusb\libusb.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include=".\libusb_static.vcxproj">
<Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="ProjectConfigurations.Base.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{861cdd5f-59a2-4f34-957e-5c1af98be0a4}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="Configuration.Application.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="Base.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemGroup>
<ClCompile Include="..\examples\sam3u_benchmark.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include=".\config.h" />
<ClInclude Include="..\libusb\libusb.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include=".\libusb_static.vcxproj">
<Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="ProjectConfigurations.Base.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{35BD5D4B-5102-4A08-81C0-AAF3285FCB01}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="Configuration.Application.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="Base.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemGroup>
<ClCompile Include="..\tests\set_option.c" />
<ClCompile Include="..\tests\testlib.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include=".\config.h" />
<ClInclude Include="..\libusb\libusb.h" />
<ClInclude Include="..\tests\libusb_testlib.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include=".\libusb_static.vcxproj">
<Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="ProjectConfigurations.Base.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{53942EFF-C810-458D-B3CB-EE5CE9F1E781}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="Configuration.Application.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="Base.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemGroup>
<ClCompile Include="..\tests\stress.c" />
<ClCompile Include="..\tests\testlib.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include=".\config.h" />
<ClInclude Include="..\libusb\libusb.h" />
<ClInclude Include="..\tests\libusb_testlib.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include=".\libusb_static.vcxproj">
<Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
Loaded 100 of 441 files, more files were not shown because too many files have changed in this diff. Show more