Files
punktfunk/packaging/windows/drivers/wdk-probe/src/lib.rs
T
enricobuehler 00cf51d610 refactor: rename pf-vdisplay-proto -> pf-driver-proto (it spans all drivers)
The shared host<->driver ABI crate already contains more than the virtual
display: the IDD-push frame ring + control plane AND the gamepad shared-memory
layouts (XusbShm / PadShm). "pf-vdisplay-proto" was a misnomer — the name now
represents all the drivers it serves.

Mechanical rename, no behavior change:
- git mv crates/pf-vdisplay-proto -> crates/pf-driver-proto (package name +
  path-deps in the host crate and the driver workspace).
- pf_vdisplay_proto -> pf_driver_proto across host + driver Rust, both Cargo.lock
  files, the workspace members, the CI path triggers (windows-drivers.yml), and
  the docs/INF comments. The runtime Global\pfvd-* shared-object names are a
  SEPARATE contract and are deliberately untouched (host<->driver name matching).
- The pf-vdisplay DRIVER crate + its INF service name (Root\pf_vdisplay,
  UmdfService=pf_vdisplay, pf_vdisplay.dll) are unchanged — only the full
  `pf_vdisplay_proto` token was replaced, never the `pf_vdisplay` driver name.

Linux-verified: cargo test -p pf-driver-proto (const size-asserts compile) +
cargo clippy -p punktfunk-host -D warnings clean; Cargo.lock regenerated. The
driver-workspace side (path-dep + imports + its Cargo.lock) is Windows-CI-gated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 05:38:21 +00:00

87 lines
4.2 KiB
Rust

//! Minimal UMDF2 driver — the M0/M1 toolchain + `/INTEGRITYCHECK` + IddCx-binding probe (see this
//! crate's Cargo.toml). DriverEntry → WdfDriverCreate → (EvtDeviceAdd) IddCxDeviceInitConfig →
//! WdfDeviceCreate → IddCxDeviceInitialize → IddCxAdapterInitAsync: enough to exercise the wdk-sys WDF
//! stub link AND prove the `iddcx` subset is callable + links against `IddCxStub`. Also force-links the
//! shared `pf-driver-proto` ABI crate (no_std + bytemuck) across the workspace boundary.
#![allow(non_snake_case, clippy::missing_safety_doc)]
mod iddcx_rt;
mod iddcx_surface_assert;
use wdk_sys::iddcx::{IDARG_IN_ADAPTER_INIT, IDARG_OUT_ADAPTER_INIT, IDD_CX_CLIENT_CONFIG};
use wdk_sys::{
NTSTATUS, PCUNICODE_STRING, PDRIVER_OBJECT, PWDFDEVICE_INIT, ULONG, WDF_DRIVER_CONFIG,
WDF_NO_HANDLE, WDF_NO_OBJECT_ATTRIBUTES, WDFDEVICE, WDFDRIVER,
call_unsafe_wdf_function_binding,
};
const STATUS_SUCCESS: NTSTATUS = 0;
/// Force `pf-driver-proto` to actually link into the driver build graph (validates the cross-workspace
/// path-dep + that the no_std bytemuck ABI crate compiles for a UMDF cdylib). `#[used]` keeps it.
#[used]
static PROTO_GUID_LO: u64 = pf_driver_proto::PF_VDISPLAY_INTERFACE_GUID_U128 as u64;
/// IddCx (stub mode) requires the driver to export the minimum IddCx framework version it needs — the
/// `#ifndef IDD_STUB` branch of `IddCxFuncEnum.h` (which normally emits it) is compiled out under
/// `IDD_STUB`, so the driver provides it. `4` matches the proven `wdf-umdf` oracle.
#[unsafe(no_mangle)]
pub static IddMinimumVersionRequired: ULONG = 4;
#[unsafe(export_name = "DriverEntry")]
pub unsafe extern "system" fn driver_entry(
driver: PDRIVER_OBJECT,
registry_path: PCUNICODE_STRING,
) -> NTSTATUS {
// SAFETY: zeroed then Size + the device-add callback set, per the WDF_DRIVER_CONFIG contract.
let mut config: WDF_DRIVER_CONFIG = unsafe { core::mem::zeroed() };
config.Size = core::mem::size_of::<WDF_DRIVER_CONFIG>() as ULONG;
config.EvtDriverDeviceAdd = Some(evt_device_add);
// SAFETY: driver + registry_path are the loader-provided pointers; config is valid for the call.
unsafe {
call_unsafe_wdf_function_binding!(
WdfDriverCreate,
driver,
registry_path,
WDF_NO_OBJECT_ATTRIBUTES,
&mut config,
WDF_NO_HANDLE.cast::<WDFDRIVER>()
)
}
}
extern "C" fn evt_device_add(_driver: WDFDRIVER, mut device_init: PWDFDEVICE_INIT) -> NTSTATUS {
// Configure the device for IddCx BEFORE WdfDeviceCreate. The required `EvtIddCx*` callbacks are left
// null in this probe — its purpose is to prove the `iddcx` DDIs are callable and link against
// IddCxStub (CI), and that a self-signed IddCx driver loads + dispatches (box); the full callback
// surface + a valid adapter come with the driver port. At runtime IddCxDeviceInitConfig will reject
// the null callbacks, but the call site is what links IddCxStub and exercises table dispatch.
let mut cfg: IDD_CX_CLIENT_CONFIG = unsafe { core::mem::zeroed() };
cfg.Size = core::mem::size_of::<IDD_CX_CLIENT_CONFIG>() as ULONG;
// SAFETY: device_init is the framework-provided init; cfg is a valid (if minimal) config.
let _ = unsafe { iddcx_rt::IddCxDeviceInitConfig(device_init, &cfg) };
let mut device: WDFDEVICE = core::ptr::null_mut();
// SAFETY: device_init is the framework-provided init; attributes null; device receives the handle.
let _ = unsafe {
call_unsafe_wdf_function_binding!(
WdfDeviceCreate,
&mut device_init,
WDF_NO_OBJECT_ATTRIBUTES,
&mut device
)
};
// SAFETY: device is the just-created WDFDEVICE.
let _ = unsafe { iddcx_rt::IddCxDeviceInitialize(device) };
// SAFETY: zeroed adapter-init args — a link/dispatch reference, not a valid adapter (see above).
let in_args: IDARG_IN_ADAPTER_INIT = unsafe { core::mem::zeroed() };
let mut out_args: IDARG_OUT_ADAPTER_INIT = unsafe { core::mem::zeroed() };
// SAFETY: in/out args are valid local storage for the call.
let _ = unsafe { iddcx_rt::IddCxAdapterInitAsync(&in_args, &mut out_args) };
STATUS_SUCCESS
}