Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: expand wdk-sys coverage to include spb-related headers #263

Merged
merged 1 commit into from
Feb 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"rust-analyzer.rustfmt.extraArgs": [
"+nightly"
"+nightly",
"--all"
],
"rust-analyzer.rustfmt.rangeFormatting.enable": true,
"evenBetterToml.formatter.crlf": true,
Expand Down
19 changes: 18 additions & 1 deletion crates/wdk-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ pub enum ApiSubset {
Wdf,
/// API subset for HID (Human Interface Device) drivers: <https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/_hid/>
Hid,
/// API subset for SPB (Serial Peripheral Bus) drivers: <https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/_spb/>
Spb,
}

impl Default for Config {
Expand Down Expand Up @@ -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"]
Expand All @@ -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)
Expand Down Expand Up @@ -1273,6 +1288,7 @@ mod tests {
config.bindgen_header_contents([ApiSubset::Base]),
r#"#include "ntifs.h"
#include "ntddk.h"
#include "ntstrsafe.h"
"#,
);
}
Expand All @@ -1292,6 +1308,7 @@ mod tests {
config.bindgen_header_contents([ApiSubset::Base, ApiSubset::Wdf]),
r#"#include "ntifs.h"
#include "ntddk.h"
#include "ntstrsafe.h"
#include "wdf.h"
"#,
);
Expand Down
1 change: 1 addition & 0 deletions crates/wdk-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ wdk-macros.workspace = true
default = []

hid = []
spb = []

nightly = ["wdk-macros/nightly"]
test-stubs = []
Expand Down
47 changes: 43 additions & 4 deletions crates/wdk-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,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> {
Expand Down Expand Up @@ -196,6 +197,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);

Expand All @@ -218,6 +221,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);

Expand Down Expand Up @@ -268,10 +273,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")
Expand Down Expand Up @@ -321,6 +322,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_count.rs` file in `OUT_DIR` which contains the
/// definition of the function `get_wdf_function_count()`. This is required to
/// be generated here since the size of the table is derived from either a
Expand Down Expand Up @@ -480,6 +517,8 @@ fn main() -> anyhow::Result<()> {
ApiSubset::Wdf,
#[cfg(feature = "hid")]
ApiSubset::Hid,
#[cfg(feature = "spb")]
ApiSubset::Spb,
])
.as_bytes(),
)?;
Expand Down
9 changes: 6 additions & 3 deletions crates/wdk-sys/src/hid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
Expand Down
10 changes: 10 additions & 0 deletions crates/wdk-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,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;

Expand Down
9 changes: 6 additions & 3 deletions crates/wdk-sys/src/ntddk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
Expand Down
37 changes: 37 additions & 0 deletions crates/wdk-sys/src/spb.rs
Original file line number Diff line number Diff line change
@@ -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::*;
9 changes: 6 additions & 3 deletions crates/wdk-sys/src/wdf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
Expand Down
9 changes: 6 additions & 3 deletions crates/wdk-sys/src/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
Expand Down
1 change: 1 addition & 0 deletions examples/sample-kmdf-driver/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]

Expand Down
1 change: 1 addition & 0 deletions examples/sample-umdf-driver/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]

Expand Down
1 change: 1 addition & 0 deletions examples/sample-wdm-driver/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]

Expand Down