feat(windows-drivers): adapter WDF context type + init-before-interface (match SudoVDA)
On-glass diagnosis narrowed decisively. PROVEN it is the driver, NOT the box: enabling the installed SudoVDA devnode -> Status=OK (the box inits a self-signed IddCx adapter right now). SudoVDA uses the IDENTICAL UmdfExtensions=IddCx0102 and is built against IddCx 1.10 (DriverVer 1.10.9.289) — exactly our config. Matched SudoVDA/the oracle on every inspectable dimension, none fixed the IddCxAdapterInitAsync INVALID_PARAMETER: caps byte-perfect (offsets+sizes vs C + framework table), minimal SDR adapter fails identically, dispatch byte-identical to the oracle (IddFunctions[idx] + IddDriverGlobals), IddMinimumVersionRequired=4 (same as oracle), version pointers, ObjectAttributes, init order, and now an adapter WDF context type (this commit). The remaining difference is the Rust binary itself vs SudoVDA C++. Next: capture IddCx ETW/WPP rejection reason (or kernel debugger), or build the oracle (wdf-umdf Rust) on-glass to isolate Rust-wide vs wdk-sys-specific. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -40,6 +40,22 @@ unsafe impl Sync for SendAdapter {}
|
|||||||
|
|
||||||
static ADAPTER: OnceLock<SendAdapter> = OnceLock::new();
|
static ADAPTER: OnceLock<SendAdapter> = OnceLock::new();
|
||||||
|
|
||||||
|
/// A WDF context type for the adapter object. SudoVDA/the oracle create the adapter via
|
||||||
|
/// `WDF_OBJECT_ATTRIBUTES::init_context_type(..)`; passing attributes with NO `ContextTypeInfo` is the one
|
||||||
|
/// structural difference left vs the working SudoVDA driver. `WDF_OBJECT_CONTEXT_TYPE_INFO` holds raw
|
||||||
|
/// pointers (so a Sync wrapper to allow a `static`); `UniqueType` self-references per `WDF_DECLARE_CONTEXT_TYPE`.
|
||||||
|
#[repr(transparent)]
|
||||||
|
struct CtxTypeInfo(wdk_sys::WDF_OBJECT_CONTEXT_TYPE_INFO);
|
||||||
|
// SAFETY: immutable 'static type metadata; the inner raw pointers are 'static and never written.
|
||||||
|
unsafe impl Sync for CtxTypeInfo {}
|
||||||
|
static ADAPTER_CTX: CtxTypeInfo = CtxTypeInfo(wdk_sys::WDF_OBJECT_CONTEXT_TYPE_INFO {
|
||||||
|
Size: core::mem::size_of::<wdk_sys::WDF_OBJECT_CONTEXT_TYPE_INFO>() as u32,
|
||||||
|
ContextName: c"PfVdAdapterCtx".as_ptr().cast(),
|
||||||
|
ContextSize: core::mem::size_of::<iddcx::IDDCX_ADAPTER>(),
|
||||||
|
UniqueType: &ADAPTER_CTX.0,
|
||||||
|
EvtDriverGetUniqueContextType: None,
|
||||||
|
});
|
||||||
|
|
||||||
/// Build the adapter caps (FP16/HDR-capable) and kick off the async adapter creation. Called from
|
/// Build the adapter caps (FP16/HDR-capable) and kick off the async adapter creation. Called from
|
||||||
/// `EvtDeviceD0Entry`; idempotent across re-entrant D0 transitions.
|
/// `EvtDeviceD0Entry`; idempotent across re-entrant D0 transitions.
|
||||||
pub fn init_adapter(device: WDFDEVICE) -> NTSTATUS {
|
pub fn init_adapter(device: WDFDEVICE) -> NTSTATUS {
|
||||||
@@ -131,6 +147,7 @@ pub fn init_adapter(device: WDFDEVICE) -> NTSTATUS {
|
|||||||
attr.ExecutionLevel = wdk_sys::_WDF_EXECUTION_LEVEL::WdfExecutionLevelInheritFromParent;
|
attr.ExecutionLevel = wdk_sys::_WDF_EXECUTION_LEVEL::WdfExecutionLevelInheritFromParent;
|
||||||
attr.SynchronizationScope =
|
attr.SynchronizationScope =
|
||||||
wdk_sys::_WDF_SYNCHRONIZATION_SCOPE::WdfSynchronizationScopeInheritFromParent;
|
wdk_sys::_WDF_SYNCHRONIZATION_SCOPE::WdfSynchronizationScopeInheritFromParent;
|
||||||
|
attr.ContextTypeInfo = &ADAPTER_CTX.0;
|
||||||
let init = iddcx::IDARG_IN_ADAPTER_INIT {
|
let init = iddcx::IDARG_IN_ADAPTER_INIT {
|
||||||
WdfDevice: device,
|
WdfDevice: device,
|
||||||
pCaps: &raw mut caps,
|
pCaps: &raw mut caps,
|
||||||
|
|||||||
@@ -92,6 +92,16 @@ extern "C" fn driver_add(_driver: WDFDRIVER, mut init: PWDFDEVICE_INIT) -> NTSTA
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IddCx must be initialized on the device BEFORE other device setup (the canonical IddCx sample order).
|
||||||
|
// We previously created the device interface first — which can leave IddCx not fully ready by D0Entry,
|
||||||
|
// making IddCxAdapterInitAsync reject (INVALID_PARAMETER) despite byte-perfect caps.
|
||||||
|
// SAFETY: device is the just-created WDFDEVICE.
|
||||||
|
let status = unsafe { wdk_iddcx::IddCxDeviceInitialize(device) };
|
||||||
|
dbglog!("[pf-vd] IddCxDeviceInitialize -> {status:#x}");
|
||||||
|
if !nt_success(status) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
// Expose the owned pf-vdisplay control interface (the host opens this GUID; STEP 4 wires the host
|
// Expose the owned pf-vdisplay control interface (the host opens this GUID; STEP 4 wires the host
|
||||||
// side in lockstep). NOT SudoVDA's GUID.
|
// side in lockstep). NOT SudoVDA's GUID.
|
||||||
let (d1, d2, d3, d4) = pf_vdisplay_proto::interface_guid_fields();
|
let (d1, d2, d3, d4) = pf_vdisplay_proto::interface_guid_fields();
|
||||||
@@ -111,12 +121,5 @@ extern "C" fn driver_add(_driver: WDFDRIVER, mut init: PWDFDEVICE_INIT) -> NTSTA
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
dbglog!("[pf-vd] WdfDeviceCreateDeviceInterface -> {status:#x}");
|
dbglog!("[pf-vd] WdfDeviceCreateDeviceInterface -> {status:#x}");
|
||||||
if !nt_success(status) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SAFETY: device is the just-created WDFDEVICE.
|
|
||||||
let status = unsafe { wdk_iddcx::IddCxDeviceInitialize(device) };
|
|
||||||
dbglog!("[pf-vd] IddCxDeviceInitialize -> {status:#x}");
|
|
||||||
status
|
status
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user