fix: internal laptop screen stuck on vendor logo with external monitor

This commit is contained in:
Alexander Daichendt 2026-06-28 16:30:53 +02:00 committed by Victoria Brekenfeld
parent dacdc3db39
commit a9f2427c00
2 changed files with 85 additions and 35 deletions

View file

@ -77,24 +77,6 @@ pub fn display_configuration(
let mut req = AtomicModeReq::new();
let plane_handles = device.plane_handles()?;
for conn in connectors
.iter()
.flat_map(|conn| device.get_connector(*conn, false).ok())
.filter(|conn| {
if let Some(enc) = conn.current_encoder()
&& let Ok(enc) = device.get_encoder(enc)
&& let Some(crtc) = enc.crtc()
{
return cleanup.contains(&crtc);
}
false
})
.map(|info| info.handle())
{
let crtc_id = get_prop(device, conn, "CRTC_ID")?;
req.add_property(conn, crtc_id, property::Value::CRTC(None));
}
// We cannot just shortcut and use the legacy api for all cleanups because of this.
// (Technically a device does not need to be atomic for planes to be used, but nobody does this otherwise.)
for plane in plane_handles {
@ -108,7 +90,7 @@ pub fn display_configuration(
_ => false,
},
)?;
if cleanup.contains(&crtc) || !is_primary {
if !is_primary && !cleanup.contains(&crtc) {
let crtc_id = get_prop(device, plane, "CRTC_ID")?;
let fb_id = get_prop(device, plane, "FB_ID")?;
req.add_property(plane, crtc_id, property::Value::CRTC(None));
@ -116,27 +98,80 @@ pub fn display_configuration(
}
}
}
for crtc in cleanup {
let mode_id = get_prop(device, crtc, "MODE_ID")?;
let active = get_prop(device, crtc, "ACTIVE")?;
req.add_property(crtc, active, property::Value::Boolean(false));
req.add_property(crtc, mode_id, property::Value::Unknown(0));
}
device.atomic_commit(AtomicCommitFlags::ALLOW_MODESET, req)?;
} else {
for crtc in res_handles.crtcs() {
#[allow(deprecated)]
let _ = device.set_cursor(*crtc, Option::<&DumbBuffer>::None);
}
for crtc in cleanup {
// null commit (necessary to trigger removal on the kernel side with the legacy api.)
let _ = device.set_crtc(crtc, None, (0, 0), &[], None);
}
disable_crtcs(device, supports_atomic, &cleanup)?;
Ok(map)
}
/// Disables the given CRTCs and detaches their connectors/planes.
pub fn disable_crtcs(
device: &mut impl ControlDevice,
supports_atomic: bool,
crtcs: &[crtc::Handle],
) -> Result<()> {
if crtcs.is_empty() {
return Ok(());
}
let res_handles = device.resource_handles()?;
if supports_atomic {
let mut req = AtomicModeReq::new();
for conn in res_handles
.connectors()
.iter()
.flat_map(|conn| device.get_connector(*conn, false).ok())
.filter(|conn| {
if let Some(enc) = conn.current_encoder()
&& let Ok(enc) = device.get_encoder(enc)
&& let Some(crtc) = enc.crtc()
{
return crtcs.contains(&crtc);
}
false
})
.map(|info| info.handle())
{
let crtc_id = get_prop(device, conn, "CRTC_ID")?;
req.add_property(conn, crtc_id, property::Value::CRTC(None));
}
for plane in device.plane_handles()? {
let info = device.get_plane(plane)?;
if let Some(crtc) = info.crtc()
&& crtcs.contains(&crtc)
{
let crtc_id = get_prop(device, plane, "CRTC_ID")?;
let fb_id = get_prop(device, plane, "FB_ID")?;
req.add_property(plane, crtc_id, property::Value::CRTC(None));
req.add_property(plane, fb_id, property::Value::Framebuffer(None));
}
}
Ok(map)
for crtc in crtcs {
let mode_id = get_prop(device, *crtc, "MODE_ID")?;
let active = get_prop(device, *crtc, "ACTIVE")?;
req.add_property(*crtc, active, property::Value::Boolean(false));
req.add_property(*crtc, mode_id, property::Value::Unknown(0));
}
device.atomic_commit(AtomicCommitFlags::ALLOW_MODESET, req)?;
} else {
for crtc in crtcs {
// null commit (necessary to trigger removal on the kernel side with the legacy api.)
let _ = device.set_crtc(*crtc, None, (0, 0), &[], None);
}
}
Ok(())
}
pub fn interface_name(device: &impl ControlDevice, connector: connector::Handle) -> Result<String> {

View file

@ -852,11 +852,26 @@ impl KmsGuard<'_> {
// first drop old surfaces
if !test_only {
for output in outputs.iter().filter(|o| !o.is_enabled()) {
device
.inner
.surfaces
.retain(|_, surface| surface.output != *output);
let mut disabled_crtcs = Vec::new();
device.inner.surfaces.retain(|crtc, surface| {
if outputs
.iter()
.any(|o| !o.is_enabled() && surface.output == *o)
{
disabled_crtcs.push(*crtc);
false
} else {
true
}
});
let supports_atomic = device.drm.device().is_atomic();
if let Err(err) = drm_helpers::disable_crtcs(
device.drm.device_mut(),
supports_atomic,
&disabled_crtcs,
) {
warn!("Failed to disable crtcs for disabled outputs: {err}");
}
}