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 bb9d3f1c..9494d9d3 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: <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 {
@@ -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)
@@ -1273,6 +1288,7 @@ mod tests {
                 config.bindgen_header_contents([ApiSubset::Base]),
                 r#"#include "ntifs.h"
 #include "ntddk.h"
+#include "ntstrsafe.h"
 "#,
             );
         }
@@ -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"
 "#,
             );
diff --git a/crates/wdk-sys/Cargo.toml b/crates/wdk-sys/Cargo.toml
index 755b825b..f7f030b8 100644
--- a/crates/wdk-sys/Cargo.toml
+++ b/crates/wdk-sys/Cargo.toml
@@ -36,6 +36,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 39784c7e..10b66cb4 100644
--- a/crates/wdk-sys/build.rs
+++ b/crates/wdk-sys/build.rs
@@ -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> {
@@ -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);
 
@@ -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);
 
@@ -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")
@@ -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
@@ -480,6 +517,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 e0a46d01..130201cd 100644
--- a/crates/wdk-sys/src/lib.rs
+++ b/crates/wdk-sys/src/lib.rs
@@ -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;
 
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 9115f247..6d3d8ebe 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"]