feat(vdisplay/driver): DDC/CI against the virtual monitor fails fast
In exclusive topology the virtual display is the ONLY monitor on the desktop, so monitor-control software (the Twinkle Tray / PowerToys PowerDisplay / Monitorian class) aims its entire DDC traffic — brightness polls, capabilities-string requests — at OUR monitor. There is no bus and no sink; the only wrong answer is a slow one (a timeout-shaped failure occupies win32k's physical-monitor path, serialized per monitor, for its full duration). Register EvtIddCxMonitorI2CTransmit/Receive and answer every probe with an immediate STATUS_NOT_SUPPORTED, making the virtual monitor the cheapest thing on the "bus" to poll. (The receive DDI has no out-arg at the callback — refusing synchronously refuses the whole transaction.) EDID needs no equivalent: the OS serves descriptor queries from the blob supplied at monitor creation without calling the driver. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -375,3 +375,30 @@ pub unsafe extern "C" fn device_io_control(
|
||||
// SAFETY: `request` is the framework-provided WDFREQUEST; `control::dispatch` completes it exactly once.
|
||||
unsafe { crate::control::dispatch(request, ioctl_code) };
|
||||
}
|
||||
|
||||
/// DDC/CI transmit toward the virtual monitor — refuse INSTANTLY (stall-immunity: DDC fail-fast).
|
||||
///
|
||||
/// In exclusive topology the virtual display is the ONLY monitor on the desktop, so
|
||||
/// monitor-control software (the Twinkle Tray / PowerToys PowerDisplay / Monitorian class) aims
|
||||
/// its entire DDC traffic — brightness polls, capabilities-string requests — at THIS monitor.
|
||||
/// There is no bus and no sink here; the only wrong answer is a slow one (a timeout-shaped
|
||||
/// failure occupies win32k's physical-monitor path, serialized per monitor, for its full
|
||||
/// duration). Registering the pair pins every probe's cost to one immediate
|
||||
/// `STATUS_NOT_SUPPORTED`. EDID needs no equivalent: the OS serves descriptor queries from the
|
||||
/// blob supplied at monitor creation without calling the driver.
|
||||
pub unsafe extern "C" fn monitor_i2c_transmit(
|
||||
_monitor: iddcx::IDDCX_MONITOR,
|
||||
_p_in: *const iddcx::IDARG_IN_I2C_TRANSMIT,
|
||||
) -> NTSTATUS {
|
||||
crate::STATUS_NOT_SUPPORTED
|
||||
}
|
||||
|
||||
/// DDC/CI receive from the virtual monitor — same contract as [`monitor_i2c_transmit`]. (The
|
||||
/// receive DDI has no out-arg at the callback — data would flow back through an async completion;
|
||||
/// a synchronous failure return refuses the whole transaction, which is exactly the point.)
|
||||
pub unsafe extern "C" fn monitor_i2c_receive(
|
||||
_monitor: iddcx::IDDCX_MONITOR,
|
||||
_p_in: *const iddcx::IDARG_IN_I2C_RECEIVE,
|
||||
) -> NTSTATUS {
|
||||
crate::STATUS_NOT_SUPPORTED
|
||||
}
|
||||
|
||||
@@ -89,6 +89,11 @@ extern "C" fn driver_add(_driver: WDFDRIVER, mut init: PWDFDEVICE_INIT) -> NTSTA
|
||||
cfg.EvtIddCxMonitorSetGammaRamp = Some(callbacks::set_gamma_ramp);
|
||||
cfg.EvtIddCxMonitorAssignSwapChain = Some(callbacks::assign_swap_chain);
|
||||
cfg.EvtIddCxMonitorUnassignSwapChain = Some(callbacks::unassign_swap_chain);
|
||||
// DDC fail-fast (stall-immunity): monitor-control software polls the virtual monitor's DDC —
|
||||
// in exclusive topology it is the ONLY monitor. These answer every probe with an immediate
|
||||
// STATUS_NOT_SUPPORTED instead of whatever slow path an unregistered interface takes.
|
||||
cfg.EvtIddCxMonitorI2CTransmit = Some(callbacks::monitor_i2c_transmit);
|
||||
cfg.EvtIddCxMonitorI2CReceive = Some(callbacks::monitor_i2c_receive);
|
||||
cfg.EvtIddCxDeviceIoControl = Some(callbacks::device_io_control);
|
||||
|
||||
// SAFETY: init is the framework device-init; cfg is fully populated + sized. (Links IddCxStub.)
|
||||
|
||||
@@ -35,6 +35,7 @@ use wdk_sys::NTSTATUS;
|
||||
// NTSTATUS codes the driver returns (wdk-sys doesn't surface all of these as constants).
|
||||
pub(crate) const STATUS_SUCCESS: NTSTATUS = 0;
|
||||
pub(crate) const STATUS_NOT_IMPLEMENTED: NTSTATUS = 0xC000_0002u32 as NTSTATUS;
|
||||
pub(crate) const STATUS_NOT_SUPPORTED: NTSTATUS = 0xC000_00BBu32 as NTSTATUS;
|
||||
pub(crate) const STATUS_NOT_FOUND: NTSTATUS = 0xC000_0225u32 as NTSTATUS;
|
||||
pub(crate) const STATUS_INVALID_PARAMETER: NTSTATUS = 0xC000_000Du32 as NTSTATUS;
|
||||
pub(crate) const STATUS_BUFFER_TOO_SMALL: NTSTATUS = 0xC000_0023u32 as NTSTATUS;
|
||||
|
||||
Reference in New Issue
Block a user