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 f3459c15..498d674d 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 a69346a2..51c77f31 100644
--- a/crates/wdk-sys/build.rs
+++ b/crates/wdk-sys/build.rs
@@ -158,6 +158,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> {
@@ -222,6 +223,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);
@@ -244,6 +247,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);
@@ -294,10 +299,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")
@@ -347,6 +348,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
@@ -516,6 +553,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"]