diff --git a/.vscode/settings.json b/.vscode/settings.json index c1d287ed..fa9e9b63 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,7 @@ { "rust-analyzer.rustfmt.extraArgs": [ - "+nightly" + "+nightly", + "--all" ], "rust-analyzer.rustfmt.rangeFormatting.enable": true, "evenBetterToml.formatter.crlf": true, diff --git a/crates/wdk-build/src/lib.rs b/crates/wdk-build/src/lib.rs index a9ca3c0c..a8115f1b 100644 --- a/crates/wdk-build/src/lib.rs +++ b/crates/wdk-build/src/lib.rs @@ -199,6 +199,8 @@ pub enum ApiSubset { Wdf, /// API subset for HID (Human Interface Device) drivers: Hid, + /// API subset for SPB (Serial Peripheral Bus) drivers: + Spb, } impl Default for Config { @@ -643,7 +645,7 @@ impl Config { match api_subset { ApiSubset::Base => match &self.driver_config { DriverConfig::Wdm | DriverConfig::Kmdf(_) => { - vec!["ntifs.h", "ntddk.h"] + vec!["ntifs.h", "ntddk.h", "ntstrsafe.h"] } DriverConfig::Umdf(_) => { vec!["windows.h"] @@ -669,6 +671,19 @@ impl Config { hid_headers } + ApiSubset::Spb => { + let mut spb_headers = vec!["spb.h", "reshub.h"]; + + if let DriverConfig::Wdm | DriverConfig::Kmdf(_) = self.driver_config { + spb_headers.extend(["pwmutil.h"]); + } + + if let DriverConfig::Kmdf(_) = self.driver_config { + spb_headers.extend(["spb/1.1/spbcx.h"]); + } + + spb_headers + } } .into_iter() .map(std::string::ToString::to_string) diff --git a/crates/wdk-sys/Cargo.toml b/crates/wdk-sys/Cargo.toml index 531c4adf..2222e58a 100644 --- a/crates/wdk-sys/Cargo.toml +++ b/crates/wdk-sys/Cargo.toml @@ -38,6 +38,7 @@ wdk-macros.workspace = true default = [] hid = [] +spb = [] nightly = ["wdk-macros/nightly"] test-stubs = [] diff --git a/crates/wdk-sys/build.rs b/crates/wdk-sys/build.rs index 3a1ec2b2..5dcb5a9c 100644 --- a/crates/wdk-sys/build.rs +++ b/crates/wdk-sys/build.rs @@ -159,6 +159,7 @@ const BINDGEN_FILE_GENERATORS_TUPLES: &[(&str, GenerateFn)] = &[ ("base.rs", generate_base), ("wdf.rs", generate_wdf), ("hid.rs", generate_hid), + ("spb.rs", generate_spb), ]; fn initialize_tracing() -> Result<(), ParseError> { @@ -223,6 +224,8 @@ fn generate_constants(out_path: &Path, config: &Config) -> Result<(), ConfigErro ApiSubset::Wdf, #[cfg(feature = "hid")] ApiSubset::Hid, + #[cfg(feature = "spb")] + ApiSubset::Spb, ]); trace!(header_contents = ?header_contents); @@ -245,6 +248,8 @@ fn generate_types(out_path: &Path, config: &Config) -> Result<(), ConfigError> { ApiSubset::Wdf, #[cfg(feature = "hid")] ApiSubset::Hid, + #[cfg(feature = "spb")] + ApiSubset::Spb, ]); trace!(header_contents = ?header_contents); @@ -295,10 +300,6 @@ fn generate_wdf(out_path: &Path, config: &Config) -> Result<(), ConfigError> { .allowlist_file("(?i).*wdf.*"); trace!(bindgen_builder = ?bindgen_builder); - // As of NI WDK, this may generate an empty file due to no non-type and non-var - // items in the wdf headers(i.e. functions are all inlined). This step is - // intentionally left here in case older/newer WDKs have non-inlined functions - // or new WDKs may introduce non-inlined functions. Ok(bindgen_builder .generate() .expect("Bindings should succeed to generate") @@ -348,6 +349,42 @@ fn generate_hid(out_path: &Path, config: &Config) -> Result<(), ConfigError> { } } +fn generate_spb(out_path: &Path, config: &Config) -> Result<(), ConfigError> { + cfg_if::cfg_if! { + if #[cfg(feature = "spb")] { + info!("Generating bindings to WDK: spb.rs"); + + let header_contents = config.bindgen_header_contents([ApiSubset::Base, ApiSubset::Wdf, ApiSubset::Spb]); + trace!(header_contents = ?header_contents); + + let bindgen_builder = { + let mut builder = bindgen::Builder::wdk_default(config)? + .with_codegen_config((CodegenConfig::TYPES | CodegenConfig::VARS).complement()) + .header_contents("spb-input.h", &header_contents); + + // Only allowlist files in the spb-specific files to avoid duplicate definitions + for header_file in config.headers(ApiSubset::Spb) + { + builder = builder.allowlist_file(format!("(?i).*{header_file}.*")); + } + builder + }; + trace!(bindgen_builder = ?bindgen_builder); + + Ok(bindgen_builder + .generate() + .expect("Bindings should succeed to generate") + .write_to_file(out_path.join("spb.rs"))?) + } else { + let _ = (out_path, config); // Silence unused variable warnings when spb feature is not enabled + + info!( + "Skipping spb.rs generation since spb feature is not enabled"); + Ok(()) + } + } +} + /// Generates a `wdf_function_table.rs` file in `OUT_DIR` which contains the /// definition of `WDF_FUNCTION_TABLE`. This is required to be generated here /// since the size of the table is derived from either a global symbol @@ -517,6 +554,8 @@ fn main() -> anyhow::Result<()> { ApiSubset::Wdf, #[cfg(feature = "hid")] ApiSubset::Hid, + #[cfg(feature = "spb")] + ApiSubset::Spb, ]) .as_bytes(), )?; diff --git a/crates/wdk-sys/src/hid.rs b/crates/wdk-sys/src/hid.rs index 1e5d67f0..236fb1b7 100644 --- a/crates/wdk-sys/src/hid.rs +++ b/crates/wdk-sys/src/hid.rs @@ -15,9 +15,12 @@ generate documentation for their bindings" )] mod bindings { - // allow wildcards for types module since underlying c code relies on all - // type definitions being in scope - #[allow(clippy::wildcard_imports)] + #[allow( + clippy::wildcard_imports, + reason = "the underlying c code relies on all type definitions being in scope, which \ + results in the bindgen generated code relying on the generated types being in \ + scope as well" + )] use crate::types::*; include!(concat!(env!("OUT_DIR"), "/hid.rs")); diff --git a/crates/wdk-sys/src/lib.rs b/crates/wdk-sys/src/lib.rs index 9f0342ac..db3ba1e3 100644 --- a/crates/wdk-sys/src/lib.rs +++ b/crates/wdk-sys/src/lib.rs @@ -41,6 +41,16 @@ pub mod windows; ))] pub mod hid; +#[cfg(all( + any( + driver_model__driver_type = "WDM", + driver_model__driver_type = "KMDF", + driver_model__driver_type = "UMDF" + ), + feature = "spb" +))] +pub mod spb; + #[cfg(feature = "test-stubs")] pub mod test_stubs; diff --git a/crates/wdk-sys/src/ntddk.rs b/crates/wdk-sys/src/ntddk.rs index d7a703e9..8f771e74 100644 --- a/crates/wdk-sys/src/ntddk.rs +++ b/crates/wdk-sys/src/ntddk.rs @@ -11,9 +11,12 @@ pub use bindings::*; #[allow(missing_docs)] mod bindings { - // allow wildcards for types module since underlying c code relies on all - // type definitions being in scope - #[allow(clippy::wildcard_imports)] + #[allow( + clippy::wildcard_imports, + reason = "the underlying c code relies on all type definitions being in scope, which \ + results in the bindgen generated code relying on the generated types being in \ + scope as well" + )] use crate::types::*; include!(concat!(env!("OUT_DIR"), "/ntddk.rs")); diff --git a/crates/wdk-sys/src/spb.rs b/crates/wdk-sys/src/spb.rs new file mode 100644 index 00000000..467e209f --- /dev/null +++ b/crates/wdk-sys/src/spb.rs @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation +// License: MIT OR Apache-2.0 + +//! Direct FFI bindings to SPB APIs from the Windows Driver Kit (WDK) +//! +//! This module contains all bindings to functions, constants, methods, +//! constructors and destructors in the following headers: `spb.h`, `spbcx.h`, +//! `reshub.h`, `pwmutil.h`. Types are not included in this module, but are +//! available in the top-level `wdk_sys` module. + +#[allow( + missing_docs, + reason = "most items in the WDK headers have no inline documentation, so bindgen is unable to \ + generate documentation for their bindings" +)] +mod bindings { + #[allow( + clippy::wildcard_imports, + reason = "the underlying c code relies on all type definitions being in scope, which \ + results in the bindgen generated code relying on the generated types being in \ + scope as well" + )] + #[allow( + unused_imports, + reason = "in certain versions of the WDK, there are no functions related to SPB that can \ + be generated by bindgen, so these types are unused " + )] + use crate::types::*; + + include!(concat!(env!("OUT_DIR"), "/spb.rs")); +} +#[allow( + unused_imports, + reason = "in certain versions of the WDK, there are no functions related to SPB that can be \ + generated by bindgen, so the `bindings` module is empty" +)] +pub use bindings::*; diff --git a/crates/wdk-sys/src/wdf.rs b/crates/wdk-sys/src/wdf.rs index 28e75fc8..986116a6 100644 --- a/crates/wdk-sys/src/wdf.rs +++ b/crates/wdk-sys/src/wdf.rs @@ -12,9 +12,12 @@ pub use bindings::*; #[allow(missing_docs)] #[allow(clippy::unreadable_literal)] mod bindings { - // allow wildcards for types module since underlying c code relies on all - // type definitions being in scope - #[allow(clippy::wildcard_imports)] + #[allow( + clippy::wildcard_imports, + reason = "the underlying c code relies on all type definitions being in scope, which \ + results in the bindgen generated code relying on the generated types being in \ + scope as well" + )] use crate::types::*; include!(concat!(env!("OUT_DIR"), "/wdf.rs")); diff --git a/crates/wdk-sys/src/windows.rs b/crates/wdk-sys/src/windows.rs index 99d2bf53..4ab80248 100644 --- a/crates/wdk-sys/src/windows.rs +++ b/crates/wdk-sys/src/windows.rs @@ -11,9 +11,12 @@ pub use bindings::*; #[allow(missing_docs)] mod bindings { - // allow wildcards for types module since underlying c code relies on all - // type definitions being in scope - #[allow(clippy::wildcard_imports)] + #[allow( + clippy::wildcard_imports, + reason = "the underlying c code relies on all type definitions being in scope, which \ + results in the bindgen generated code relying on the generated types being in \ + scope as well" + )] use crate::types::*; include!(concat!(env!("OUT_DIR"), "/windows.rs")); diff --git a/examples/sample-kmdf-driver/Cargo.toml b/examples/sample-kmdf-driver/Cargo.toml index 42c92bb6..cff1287e 100644 --- a/examples/sample-kmdf-driver/Cargo.toml +++ b/examples/sample-kmdf-driver/Cargo.toml @@ -33,6 +33,7 @@ wdk-sys = { path = "../../crates/wdk-sys", version = "0.3.0" } default = [] hid = ["wdk-sys/hid"] +spb = ["wdk-sys/spb"] nightly = ["wdk/nightly", "wdk-sys/nightly"] diff --git a/examples/sample-umdf-driver/Cargo.toml b/examples/sample-umdf-driver/Cargo.toml index 9b8d9003..3ae09d09 100644 --- a/examples/sample-umdf-driver/Cargo.toml +++ b/examples/sample-umdf-driver/Cargo.toml @@ -31,6 +31,7 @@ wdk-sys = { path = "../../crates/wdk-sys", version = "0.3.0" } default = [] hid = ["wdk-sys/hid"] +spb = ["wdk-sys/spb"] nightly = ["wdk/nightly", "wdk-sys/nightly"] diff --git a/examples/sample-wdm-driver/Cargo.toml b/examples/sample-wdm-driver/Cargo.toml index 96457bd1..5fd3a516 100644 --- a/examples/sample-wdm-driver/Cargo.toml +++ b/examples/sample-wdm-driver/Cargo.toml @@ -32,6 +32,7 @@ wdk-sys = { path = "../../crates/wdk-sys", version = "0.3.0" } default = [] hid = ["wdk-sys/hid"] +spb = ["wdk-sys/spb"] nightly = ["wdk/nightly", "wdk-sys/nightly"]