//! # Connector //! //! Represents the physical output, such as a DisplayPort or VGA connector. //! //! A Connector is the physical connection between the display controller and //! a display. These objects keep track of connection information and state, //! including the modes that the current display supports. use crate::control; use drm_ffi as ffi; /// A handle to a connector #[repr(transparent)] #[derive(Copy, Clone, Hash, PartialEq, Eq)] pub struct Handle(control::RawResourceHandle); // Safety: Handle is repr(transparent) over NonZeroU32 unsafe impl bytemuck::ZeroableInOption for Handle {} unsafe impl bytemuck::PodInOption for Handle {} impl From for control::RawResourceHandle { fn from(handle: Handle) -> Self { handle.0 } } impl From for u32 { fn from(handle: Handle) -> Self { handle.0.into() } } impl From for Handle { fn from(handle: control::RawResourceHandle) -> Self { Handle(handle) } } impl control::ResourceHandle for Handle { const FFI_TYPE: u32 = ffi::DRM_MODE_OBJECT_CONNECTOR; } impl std::fmt::Debug for Handle { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.debug_tuple("connector::Handle").field(&self.0).finish() } } /// Information about a connector #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Info { pub(crate) handle: Handle, pub(crate) interface: Interface, pub(crate) interface_id: u32, pub(crate) connection: State, pub(crate) size: Option<(u32, u32)>, pub(crate) modes: Vec, pub(crate) encoders: Vec, pub(crate) curr_enc: Option, pub(crate) subpixel: SubPixel, } impl std::fmt::Display for Info { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}-{}", self.interface.as_str(), self.interface_id) } } impl Info { /// Returns the handle to this connector. pub fn handle(&self) -> Handle { self.handle } /// Returns the type of `Interface` of this connector. pub fn interface(&self) -> Interface { self.interface } /// Returns the interface ID of this connector. /// /// When multiple connectors have the same `Interface`, they will have /// different interface IDs. pub fn interface_id(&self) -> u32 { self.interface_id } /// Returns the `State` of this connector. pub fn state(&self) -> State { self.connection } /// Returns the size of the display (in millimeters) if connected. pub fn size(&self) -> Option<(u32, u32)> { self.size } /// Returns a list of encoders that can be possibly used by this connector. pub fn encoders(&self) -> &[control::encoder::Handle] { &self.encoders } /// Returns a list of modes this connector reports as supported. pub fn modes(&self) -> &[control::Mode] { &self.modes } /// Returns the current encoder attached to this connector. pub fn current_encoder(&self) -> Option { self.curr_enc } /// Subpixel order of the connected sink pub fn subpixel(&self) -> SubPixel { self.subpixel } } /// A physical interface type. #[allow(missing_docs)] #[allow(clippy::upper_case_acronyms)] #[non_exhaustive] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub enum Interface { Unknown, VGA, DVII, DVID, DVIA, Composite, SVideo, LVDS, Component, NinePinDIN, DisplayPort, HDMIA, HDMIB, TV, EmbeddedDisplayPort, Virtual, DSI, DPI, Writeback, SPI, USB, } impl Interface { /// Get interface name as string pub fn as_str(&self) -> &'static str { // source: https://github.com/torvalds/linux/blob/489fa31ea873282b41046d412ec741f93946fc2d/drivers/gpu/drm/drm_connector.c#L89 match self { 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", } } } impl From for Interface { fn from(n: u32) -> Self { match n { ffi::DRM_MODE_CONNECTOR_Unknown => Interface::Unknown, ffi::DRM_MODE_CONNECTOR_VGA => Interface::VGA, ffi::DRM_MODE_CONNECTOR_DVII => Interface::DVII, ffi::DRM_MODE_CONNECTOR_DVID => Interface::DVID, ffi::DRM_MODE_CONNECTOR_DVIA => Interface::DVIA, ffi::DRM_MODE_CONNECTOR_Composite => Interface::Composite, ffi::DRM_MODE_CONNECTOR_SVIDEO => Interface::SVideo, ffi::DRM_MODE_CONNECTOR_LVDS => Interface::LVDS, ffi::DRM_MODE_CONNECTOR_Component => Interface::Component, ffi::DRM_MODE_CONNECTOR_9PinDIN => Interface::NinePinDIN, ffi::DRM_MODE_CONNECTOR_DisplayPort => Interface::DisplayPort, ffi::DRM_MODE_CONNECTOR_HDMIA => Interface::HDMIA, ffi::DRM_MODE_CONNECTOR_HDMIB => Interface::HDMIB, ffi::DRM_MODE_CONNECTOR_TV => Interface::TV, ffi::DRM_MODE_CONNECTOR_eDP => Interface::EmbeddedDisplayPort, ffi::DRM_MODE_CONNECTOR_VIRTUAL => Interface::Virtual, ffi::DRM_MODE_CONNECTOR_DSI => Interface::DSI, ffi::DRM_MODE_CONNECTOR_DPI => Interface::DPI, ffi::DRM_MODE_CONNECTOR_WRITEBACK => Interface::Writeback, ffi::DRM_MODE_CONNECTOR_SPI => Interface::SPI, ffi::DRM_MODE_CONNECTOR_USB => Interface::USB, _ => Interface::Unknown, } } } impl From for u32 { fn from(interface: Interface) -> Self { match interface { Interface::Unknown => ffi::DRM_MODE_CONNECTOR_Unknown, Interface::VGA => ffi::DRM_MODE_CONNECTOR_VGA, Interface::DVII => ffi::DRM_MODE_CONNECTOR_DVII, Interface::DVID => ffi::DRM_MODE_CONNECTOR_DVID, Interface::DVIA => ffi::DRM_MODE_CONNECTOR_DVIA, Interface::Composite => ffi::DRM_MODE_CONNECTOR_Composite, Interface::SVideo => ffi::DRM_MODE_CONNECTOR_SVIDEO, Interface::LVDS => ffi::DRM_MODE_CONNECTOR_LVDS, Interface::Component => ffi::DRM_MODE_CONNECTOR_Component, Interface::NinePinDIN => ffi::DRM_MODE_CONNECTOR_9PinDIN, Interface::DisplayPort => ffi::DRM_MODE_CONNECTOR_DisplayPort, Interface::HDMIA => ffi::DRM_MODE_CONNECTOR_HDMIA, Interface::HDMIB => ffi::DRM_MODE_CONNECTOR_HDMIB, Interface::TV => ffi::DRM_MODE_CONNECTOR_TV, Interface::EmbeddedDisplayPort => ffi::DRM_MODE_CONNECTOR_eDP, Interface::Virtual => ffi::DRM_MODE_CONNECTOR_VIRTUAL, Interface::DSI => ffi::DRM_MODE_CONNECTOR_DSI, Interface::DPI => ffi::DRM_MODE_CONNECTOR_DPI, Interface::Writeback => ffi::DRM_MODE_CONNECTOR_WRITEBACK, Interface::SPI => ffi::DRM_MODE_CONNECTOR_SPI, Interface::USB => ffi::DRM_MODE_CONNECTOR_USB, } } } /// The state of a connector. #[allow(missing_docs)] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub enum State { Connected, Disconnected, Unknown, } impl From for State { fn from(n: u32) -> Self { // These variables are not defined in drm_mode.h for some reason. // They were copied from libdrm's xf86DrmMode.h match n { 1 => State::Connected, 2 => State::Disconnected, _ => State::Unknown, } } } impl From for u32 { fn from(state: State) -> Self { // These variables are not defined in drm_mode.h for some reason. // They were copied from libdrm's xf86DrmMode.h match state { State::Connected => 1, State::Disconnected => 2, State::Unknown => 3, } } } /// Subpixel order of the connected sink #[non_exhaustive] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub enum SubPixel { /// Unknown geometry Unknown, /// Horizontal RGB HorizontalRgb, /// Horizontal BGR HorizontalBgr, /// Vertical RGB VerticalRgb, /// Vertical BGR VerticalBgr, /// No geometry None, /// Encountered value not supported by drm-rs NotImplemented, } impl SubPixel { pub(super) fn from_raw(n: u32) -> Self { // These values are not defined in drm_mode.h // They were copied from linux's drm_connector.h // Don't mistake those for ones used in xf86DrmMode.h (libdrm offsets those by 1) match n { 0 => Self::Unknown, 1 => Self::HorizontalRgb, 2 => Self::HorizontalBgr, 3 => Self::VerticalRgb, 4 => Self::VerticalBgr, 5 => Self::None, _ => Self::NotImplemented, } } }