use drm::control::Device as _;
use drm::control::connector::{Interface, State};
use drmkit_core::{Device, Result};
use crate::profile::errno;
use drm::control::Mode;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
pub enum Probe {
#[default]
Force,
Cached,
}
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub struct ConnectorModes {
pub connector_id: u32,
pub interface: Interface,
pub interface_id: u32,
pub connected: bool,
pub modes: Vec<Mode>,
}
impl ConnectorModes {
#[must_use]
pub fn name(&self) -> String {
format!("{}-{}", self.interface.as_str(), self.interface_id)
}
}
pub fn query_connector_modes(device: &Device, probe: Probe) -> Result<Vec<ConnectorModes>> {
let resources = device.resource_handles().map_err(|error| errno(&error))?;
let force = probe == Probe::Force;
let mut out = Vec::with_capacity(resources.connectors().len());
for handle in resources.connectors() {
let Ok(connector) = device.get_connector(*handle, force) else {
continue;
};
out.push(ConnectorModes {
connector_id: (*handle).into(),
interface: connector.interface(),
interface_id: connector.interface_id(),
connected: connector.state() == State::Connected,
modes: connector.modes().to_vec(),
});
}
Ok(out)
}
#[cfg(test)]
mod tests {
use super::ConnectorModes;
use drm::control::connector::Interface;
const LIBDRM: [(Interface, &str); 21] = [
(Interface::Unknown, "Unknown"),
(Interface::VGA, "VGA"),
(Interface::DVII, "DVI-I"),
(Interface::DVID, "DVI-D"),
(Interface::DVIA, "DVI-A"),
(Interface::Composite, "Composite"),
(Interface::SVideo, "SVIDEO"),
(Interface::LVDS, "LVDS"),
(Interface::Component, "Component"),
(Interface::NinePinDIN, "DIN"),
(Interface::DisplayPort, "DP"),
(Interface::HDMIA, "HDMI-A"),
(Interface::HDMIB, "HDMI-B"),
(Interface::TV, "TV"),
(Interface::EmbeddedDisplayPort, "eDP"),
(Interface::Virtual, "Virtual"),
(Interface::DSI, "DSI"),
(Interface::DPI, "DPI"),
(Interface::Writeback, "Writeback"),
(Interface::SPI, "SPI"),
(Interface::USB, "USB"),
];
fn connector(interface: Interface, interface_id: u32) -> ConnectorModes {
ConnectorModes {
connector_id: 1,
interface,
interface_id,
connected: false,
modes: Vec::new(),
}
}
#[test]
fn every_connector_type_is_named_the_way_libdrm_names_it() {
for (interface, expected) in LIBDRM {
assert_eq!(
connector(interface, 1).name(),
format!("{expected}-1"),
"{interface:?}"
);
}
}
#[test]
fn the_name_carries_the_instance() {
assert_eq!(connector(Interface::HDMIA, 1).name(), "HDMI-A-1");
assert_eq!(connector(Interface::HDMIA, 2).name(), "HDMI-A-2");
assert_eq!(connector(Interface::EmbeddedDisplayPort, 2).name(), "eDP-2");
}
#[test]
fn a_type_nothing_knows_about_still_has_a_name() {
assert_eq!(
connector(Interface::from(0xFFFF_u32), 1).name(),
"Unknown-1"
);
}
}