mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-10-19 05:57:48 +02:00
chore(rust): update toolchain and dependencies with preserved vendor sources
This commit is contained in:
1 parent
5caa2ed588
commit
08032f1877
441 files changed
+43030
-520
No files matched your search
+5
-3
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
Generated
+92
-75
@@ -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",
|
||||
]
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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,4 +1,4 @@
|
||||
[toolchain]
|
||||
channel = "1.98.1"
|
||||
channel = "1.99.0"
|
||||
profile = "minimal"
|
||||
components = ["rustfmt", "clippy"]
|
||||
Vendored
+18
-2
@@ -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"
|
||||
}
|
||||
@@ -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
@@ -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"
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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!
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -0,0 +1,33 @@
|
||||
# libusb
|
||||
|
||||
[](https://travis-ci.org/libusb/libusb)
|
||||
[](https://ci.appveyor.com/project/LudovicRousseau/libusb)
|
||||
[](https://scan.coverity.com/projects/libusb-libusb)
|
||||
|
||||
libusb is a library for USB device access from Linux, macOS,
|
||||
Windows, OpenBSD/NetBSD, Haiku, Solaris userspace, and WebAssembly
|
||||
via WebUSB.
|
||||
It is written in C (Haiku backend in C++) and licensed under the GNU
|
||||
Lesser General Public License version 2.1 or, at your option, any later
|
||||
version (see [COPYING](COPYING)).
|
||||
|
||||
libusb is abstracted internally in such a way that it can hopefully
|
||||
be ported to other operating systems. Please see the [PORTING](PORTING)
|
||||
file for more information.
|
||||
|
||||
libusb homepage:
|
||||
https://libusb.info/
|
||||
|
||||
Developers will wish to consult the API documentation:
|
||||
http://api.libusb.info
|
||||
|
||||
Use the mailing list for questions, comments, etc:
|
||||
http://mailing-list.libusb.info
|
||||
|
||||
- Hans de Goede <hdegoede@redhat.com>
|
||||
- Xiaofan Chen <xiaofanc@gmail.com>
|
||||
- Ludovic Rousseau <ludovic.rousseau@gmail.com>
|
||||
- Nathan Hjelm <hjelmn@cs.unm.edu>
|
||||
- Chris Dickens <christopher.a.dickens@gmail.com>
|
||||
|
||||
(Please use the mailing list rather than mailing developers directly)
|
||||
@@ -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
|
||||
+896
@@ -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;
|
||||
};
|
||||
+532
@@ -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)'>'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>
|
||||
+7
@@ -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)'<'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)'>='142'">
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
+33
@@ -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>
|
||||
+7
@@ -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>
|
||||
+122
@@ -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
Reference in new issue
Block a user