Skip to content
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
17 changes: 17 additions & 0 deletions crates/wdk-build/src/bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,23 @@ impl BuilderExt for Builder {
.blocklist_item("ExAllocatePoolWithQuotaTag") // Deprecated
.blocklist_item("ExAllocatePoolWithTagPriority") // Deprecated
.blocklist_item("ExAllocatePool") // Deprecated
.blocklist_item("USBD_CalculateUsbBandwidth") // Deprecated
.blocklist_item("USBD_CreateConfigurationRequest") // Deprecated
.blocklist_item("USBD_Debug_LogEntry") // Deprecated
.blocklist_item("USBD_GetUSBDIVersion") // Deprecated
.blocklist_item("USBD_ParseConfigurationDescriptor") // Deprecated
.blocklist_item("USBD_QueryBusTime") // Deprecated
.blocklist_item("USBD_RegisterHcFilter") // Deprecated
.blocklist_item("IOCTL_USB_DIAG_IGNORE_HUBS_OFF") // Deprecated/Internal-Use-Only
.blocklist_item("IOCTL_USB_DIAG_IGNORE_HUBS_ON") // Deprecated/Internal-Use-Only
.blocklist_item("IOCTL_USB_DIAGNOSTIC_MODE_OFF") // Deprecated/Internal-Use-Only
.blocklist_item("IOCTL_USB_DIAGNOSTIC_MODE_ON") // Deprecated/Internal-Use-Only
.blocklist_item("IOCTL_USB_GET_HUB_CAPABILITIES") // Deprecated/Internal-Use-Only
.blocklist_item("IOCTL_USB_HCD_DISABLE_PORT") // Deprecated/Internal-Use-Only
.blocklist_item("IOCTL_USB_HCD_ENABLE_PORT") // Deprecated/Internal-Use-Only
.blocklist_item("IOCTL_USB_HCD_GET_STATS_1") // Deprecated/Internal-Use-Only
.blocklist_item("IOCTL_USB_HCD_GET_STATS_2") // Deprecated/Internal-Use-Only
.blocklist_item("IOCTL_USB_RESET_HUB") // Deprecated/Internal-Use-Only
.opaque_type("_KGDTENTRY64") // No definition in WDK
.opaque_type("_KIDTENTRY64") // No definition in WDK
// FIXME: bitfield generated with non-1byte alignment in _MCG_CAP
Expand Down
280 changes: 200 additions & 80 deletions crates/wdk-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ pub enum ApiSubset {
Spb,
/// API subset for Storage drivers: <https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/_storage/>
Storage,
/// API subset for USB (Universal Serial Bus) drivers: <https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/_usbref/>
Usb,
}

impl Default for Config {
Expand Down Expand Up @@ -407,6 +409,21 @@ impl Config {
.canonicalize()?
.strip_extended_length_path_prefix()?,
);

// `ufxclient.h` relies on `ufxbase.h` being on the headers search path. The WDK
// normally does not automatically include this search path, but it is required
// here so that the headers can be processed successfully.
let ufx_include_path = km_or_um_include_path.join("ufx/1.1");
if !ufx_include_path.is_dir() {
return Err(ConfigError::DirectoryNotFound {
directory: ufx_include_path.to_string_lossy().into(),
});
}
include_paths.push(
ufx_include_path
.canonicalize()?
.strip_extended_length_path_prefix()?,
);
}
DriverConfig::Umdf(umdf_config) => {
let umdf_include_path = include_directory.join(format!(
Expand Down Expand Up @@ -627,8 +644,8 @@ impl Config {
"--warn-=no-ignored-attributes",
"--warn-=no-ignored-pragma-intrinsic",
"--warn-=no-visibility",
"--warn-=no-microsoft-anon-tag",
"--warn-=no-microsoft-enum-forward-reference",
"--warn-=no-switch",
"--warn-=no-comment",
// Don't warn for deprecated declarations. Deprecated items should be explicitly
// blocklisted (i.e. by the bindgen invocation). Any non-blocklisted function
// definitions will trigger a -WDeprecated warning
Expand All @@ -637,6 +654,8 @@ impl Config {
// `_variable` are separate tokens already, and don't need `##` to concatenate
// them)
"--warn-=no-invalid-token-paste",
// Windows SDK & DDK headers rely on Microsoft extensions to C/C++
"--warn-=no-microsoft",
]
.into_iter()
.map(std::string::ToString::to_string)
Expand All @@ -649,99 +668,200 @@ impl Config {
/// determine which headers to yield
pub fn headers(&self, api_subset: ApiSubset) -> impl Iterator<Item = String> {
match api_subset {
ApiSubset::Base => match &self.driver_config {
DriverConfig::Wdm | DriverConfig::Kmdf(_) => {
vec!["ntifs.h", "ntddk.h", "ntstrsafe.h"]
}
DriverConfig::Umdf(_) => {
vec!["windows.h"]
}
},
ApiSubset::Wdf => {
if let DriverConfig::Kmdf(_) | DriverConfig::Umdf(_) = self.driver_config {
vec!["wdf.h"]
} else {
vec![]
}
ApiSubset::Base => self.base_headers(),
ApiSubset::Wdf => self.wdf_headers(),
ApiSubset::Gpio => self.gpio_headers(),
ApiSubset::Hid => self.hid_headers(),
ApiSubset::ParallelPorts => self.parallel_ports_headers(),
ApiSubset::Spb => self.spb_headers(),
ApiSubset::Storage => self.storage_headers(),
ApiSubset::Usb => self.usb_headers(),
}
.into_iter()
.map(str::to_string)
}

fn base_headers(&self) -> Vec<&'static str> {
match &self.driver_config {
DriverConfig::Wdm | DriverConfig::Kmdf(_) => {
vec!["ntifs.h", "ntddk.h", "ntstrsafe.h"]
}
ApiSubset::Gpio => {
let mut gpio_headers = vec!["gpio.h"];
DriverConfig::Umdf(_) => {
vec!["windows.h"]
}
}
}

if let DriverConfig::Kmdf(_) = self.driver_config {
gpio_headers.extend(["gpioclx.h"]);
}
fn wdf_headers(&self) -> Vec<&'static str> {
if matches!(
self.driver_config,
DriverConfig::Kmdf(_) | DriverConfig::Umdf(_)
) {
vec!["wdf.h"]
} else {
vec![]
}
}

gpio_headers
}
ApiSubset::Hid => {
let mut hid_headers = vec!["hidclass.h", "hidsdi.h", "hidpi.h", "vhf.h"];
fn gpio_headers(&self) -> Vec<&'static str> {
let mut headers = vec!["gpio.h"];
if matches!(self.driver_config, DriverConfig::Kmdf(_)) {
headers.extend(["gpioclx.h"]);
}
headers
}

if let DriverConfig::Wdm | DriverConfig::Kmdf(_) = self.driver_config {
hid_headers.extend(["hidpddi.h", "hidport.h", "kbdmou.h", "ntdd8042.h"]);
}
fn hid_headers(&self) -> Vec<&'static str> {
let mut headers = vec!["hidclass.h", "hidsdi.h", "hidpi.h", "vhf.h"];
if matches!(
self.driver_config,
DriverConfig::Wdm | DriverConfig::Kmdf(_)
) {
headers.extend(["hidpddi.h", "hidport.h", "kbdmou.h", "ntdd8042.h"]);
}

if let DriverConfig::Kmdf(_) = self.driver_config {
hid_headers.extend(["HidSpiCx/1.0/hidspicx.h"]);
}
if matches!(self.driver_config, DriverConfig::Kmdf(_)) {
headers.extend(["HidSpiCx/1.0/hidspicx.h"]);
}
headers
}

hid_headers
}
ApiSubset::ParallelPorts => {
let mut parallel_ports_headers = vec!["ntddpar.h", "ntddser.h"];
fn parallel_ports_headers(&self) -> Vec<&'static str> {
let mut headers = vec!["ntddpar.h", "ntddser.h"];
if matches!(
self.driver_config,
DriverConfig::Wdm | DriverConfig::Kmdf(_)
) {
headers.extend(["parallel.h"]);
}
headers
}

if let DriverConfig::Wdm | DriverConfig::Kmdf(_) = self.driver_config {
parallel_ports_headers.extend(["parallel.h"]);
}
fn spb_headers(&self) -> Vec<&'static str> {
let mut headers = vec!["spb.h", "reshub.h"];
if matches!(
self.driver_config,
DriverConfig::Wdm | DriverConfig::Kmdf(_)
) {
headers.extend(["pwmutil.h"]);
}
if matches!(self.driver_config, DriverConfig::Kmdf(_)) {
headers.extend(["spb/1.1/spbcx.h"]);
}
headers
}

parallel_ports_headers
}
ApiSubset::Spb => {
let mut spb_headers = vec!["spb.h", "reshub.h"];
fn storage_headers(&self) -> Vec<&'static str> {
let mut headers = vec![
"ehstorioctl.h",
"ntddcdrm.h",
"ntddcdvd.h",
"ntdddisk.h",
"ntddmmc.h",
"ntddscsi.h",
"ntddstor.h",
"ntddtape.h",
"ntddvol.h",
"ufs.h",
];
if matches!(
self.driver_config,
DriverConfig::Wdm | DriverConfig::Kmdf(_)
) {
headers.extend([
"mountdev.h",
"mountmgr.h",
"ntddchgr.h",
"ntdddump.h",
"storduid.h",
"storport.h",
]);
}
if matches!(self.driver_config, DriverConfig::Kmdf(_)) {
headers.extend(["ehstorbandmgmt.h"]);
}
headers
}

if let DriverConfig::Wdm | DriverConfig::Kmdf(_) = self.driver_config {
spb_headers.extend(["pwmutil.h"]);
}
fn usb_headers(&self) -> Vec<&'static str> {
let mut headers = vec![
"usb.h",
"usbfnbase.h",
"usbioctl.h",
"usbspec.h",
"Usbpmapi.h",
];

if matches!(
self.driver_config,
DriverConfig::Wdm | DriverConfig::Kmdf(_)
) {
headers.extend(["usbbusif.h", "usbdlib.h", "usbfnattach.h", "usbfnioctl.h"]);
}

if let DriverConfig::Kmdf(_) = self.driver_config {
spb_headers.extend(["spb/1.1/spbcx.h"]);
}
if matches!(
self.driver_config,
DriverConfig::Kmdf(_) | DriverConfig::Umdf(_)
) {
headers.extend(["wdfusb.h"]);
}

spb_headers
if matches!(self.driver_config, DriverConfig::Kmdf(_)) {
headers.extend([
"ucm/1.0/UcmCx.h",
"UcmTcpci/1.0/UcmTcpciCx.h",
"UcmUcsi/1.0/UcmucsiCx.h",
"ucx/1.6/ucxclass.h",
"ude/1.1/UdeCx.h",
"ufx/1.1/ufxbase.h",
"ufxproprietarycharger.h",
"urs/1.0/UrsCx.h",
]);

if Self::should_include_ufxclient() {
headers.extend(["ufx/1.1/ufxclient.h"]);
}
ApiSubset::Storage => {
let mut storage_headers = vec![
"ehstorioctl.h",
"ntddcdrm.h",
"ntddcdvd.h",
"ntdddisk.h",
"ntddmmc.h",
"ntddscsi.h",
"ntddstor.h",
"ntddtape.h",
"ntddvol.h",
"ufs.h",
];

if let DriverConfig::Wdm | DriverConfig::Kmdf(_) = self.driver_config {
storage_headers.extend([
"mountdev.h",
"mountmgr.h",
"ntddchgr.h",
"ntdddump.h",
"storduid.h",
"storport.h",
]);
}

if let DriverConfig::Kmdf(_) = self.driver_config {
storage_headers.extend(["ehstorbandmgmt.h"]);
}
}
headers
}

storage_headers
/// Determines whether to include the ufxclient.h header based on the Clang
/// version used by bindgen.
///
/// The ufxclient.h header contains FORCEINLINE annotations that are invalid
/// according to the C standard. While MSVC silently ignores these in C
/// mode, older versions of Clang (pre-20.0) will error, even with MSVC
/// compatibility enabled.
///
/// This function checks if the current Clang version is 20.0 or newer,
/// where the issue was fixed. See
/// <https://github.com/llvm/llvm-project/issues/124869> for details.
fn should_include_ufxclient() -> bool {
const MINIMUM_CLANG_MAJOR_VERISON_WITH_INVALID_INLINE_FIX: u32 = 20;

let clang_version = ::bindgen::clang_version();
match clang_version.parsed {
Some((major, _minor))
if major >= MINIMUM_CLANG_MAJOR_VERISON_WITH_INVALID_INLINE_FIX =>
{
true
}
Some(_) => {
tracing::info!(
"Skipping ufxclient.h due to FORCEINLINE bug in {}",
clang_version.full
);
false
}
None => {
tracing::warn!(
"Failed to parse semver Major and Minor components from full Clang version \
string: {}",
clang_version.full
);
false
}
}
.into_iter()
.map(std::string::ToString::to_string)
}

/// Returns a [`String`] containing the contents of a header file designed
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 @@ -40,6 +40,7 @@ hid = []
parallel-ports = ["gpio"]
spb = []
storage = []
usb = []

nightly = ["wdk-macros/nightly"]
test-stubs = []
Expand Down
Loading