1 //! # Connector
2 //!
3 //! Represents the physical output, such as a DisplayPort or VGA connector.
4 //!
5 //! A Connector is the physical connection between the display controller and
6 //! a display. These objects keep track of connection information and state,
7 //! including the modes that the current display supports.
8 
9 use crate::control;
10 use drm_ffi as ffi;
11 
12 /// A handle to a connector
13 #[repr(transparent)]
14 #[derive(Copy, Clone, Hash, PartialEq, Eq)]
15 pub struct Handle(control::RawResourceHandle);
16 
17 // Safety: Handle is repr(transparent) over NonZeroU32
18 unsafe impl bytemuck::ZeroableInOption for Handle {}
19 unsafe impl bytemuck::PodInOption for Handle {}
20 
21 impl From<Handle> for control::RawResourceHandle {
from(handle: Handle) -> Self22     fn from(handle: Handle) -> Self {
23         handle.0
24     }
25 }
26 
27 impl From<Handle> for u32 {
from(handle: Handle) -> Self28     fn from(handle: Handle) -> Self {
29         handle.0.into()
30     }
31 }
32 
33 impl From<control::RawResourceHandle> for Handle {
from(handle: control::RawResourceHandle) -> Self34     fn from(handle: control::RawResourceHandle) -> Self {
35         Handle(handle)
36     }
37 }
38 
39 impl control::ResourceHandle for Handle {
40     const FFI_TYPE: u32 = ffi::DRM_MODE_OBJECT_CONNECTOR;
41 }
42 
43 impl std::fmt::Debug for Handle {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result44     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
45         f.debug_tuple("connector::Handle").field(&self.0).finish()
46     }
47 }
48 
49 /// Information about a connector
50 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
51 pub struct Info {
52     pub(crate) handle: Handle,
53     pub(crate) interface: Interface,
54     pub(crate) interface_id: u32,
55     pub(crate) connection: State,
56     pub(crate) size: Option<(u32, u32)>,
57     pub(crate) modes: Vec<control::Mode>,
58     pub(crate) encoders: Vec<control::encoder::Handle>,
59     pub(crate) curr_enc: Option<control::encoder::Handle>,
60     pub(crate) subpixel: SubPixel,
61 }
62 
63 impl std::fmt::Display for Info {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result64     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65         write!(f, "{}-{}", self.interface.as_str(), self.interface_id)
66     }
67 }
68 
69 impl Info {
70     /// Returns the handle to this connector.
handle(&self) -> Handle71     pub fn handle(&self) -> Handle {
72         self.handle
73     }
74 
75     /// Returns the type of `Interface` of this connector.
interface(&self) -> Interface76     pub fn interface(&self) -> Interface {
77         self.interface
78     }
79 
80     /// Returns the interface ID of this connector.
81     ///
82     /// When multiple connectors have the same `Interface`, they will have
83     /// different interface IDs.
interface_id(&self) -> u3284     pub fn interface_id(&self) -> u32 {
85         self.interface_id
86     }
87 
88     /// Returns the `State` of this connector.
state(&self) -> State89     pub fn state(&self) -> State {
90         self.connection
91     }
92 
93     /// Returns the size of the display (in millimeters) if connected.
size(&self) -> Option<(u32, u32)>94     pub fn size(&self) -> Option<(u32, u32)> {
95         self.size
96     }
97 
98     /// Returns a list of encoders that can be possibly used by this connector.
encoders(&self) -> &[control::encoder::Handle]99     pub fn encoders(&self) -> &[control::encoder::Handle] {
100         &self.encoders
101     }
102 
103     /// Returns a list of modes this connector reports as supported.
modes(&self) -> &[control::Mode]104     pub fn modes(&self) -> &[control::Mode] {
105         &self.modes
106     }
107 
108     /// Returns the current encoder attached to this connector.
current_encoder(&self) -> Option<control::encoder::Handle>109     pub fn current_encoder(&self) -> Option<control::encoder::Handle> {
110         self.curr_enc
111     }
112 
113     /// Subpixel order of the connected sink
subpixel(&self) -> SubPixel114     pub fn subpixel(&self) -> SubPixel {
115         self.subpixel
116     }
117 }
118 
119 /// A physical interface type.
120 #[allow(missing_docs)]
121 #[allow(clippy::upper_case_acronyms)]
122 #[non_exhaustive]
123 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
124 pub enum Interface {
125     Unknown,
126     VGA,
127     DVII,
128     DVID,
129     DVIA,
130     Composite,
131     SVideo,
132     LVDS,
133     Component,
134     NinePinDIN,
135     DisplayPort,
136     HDMIA,
137     HDMIB,
138     TV,
139     EmbeddedDisplayPort,
140     Virtual,
141     DSI,
142     DPI,
143     Writeback,
144     SPI,
145     USB,
146 }
147 
148 impl Interface {
149     /// Get interface name as string
as_str(&self) -> &'static str150     pub fn as_str(&self) -> &'static str {
151         // source: https://github.com/torvalds/linux/blob/489fa31ea873282b41046d412ec741f93946fc2d/drivers/gpu/drm/drm_connector.c#L89
152         match self {
153             Interface::Unknown => "Unknown",
154             Interface::VGA => "VGA",
155             Interface::DVII => "DVI-I",
156             Interface::DVID => "DVI-D",
157             Interface::DVIA => "DVI-A",
158             Interface::Composite => "Composite",
159             Interface::SVideo => "SVIDEO",
160             Interface::LVDS => "LVDS",
161             Interface::Component => "Component",
162             Interface::NinePinDIN => "DIN",
163             Interface::DisplayPort => "DP",
164             Interface::HDMIA => "HDMI-A",
165             Interface::HDMIB => "HDMI-B",
166             Interface::TV => "TV",
167             Interface::EmbeddedDisplayPort => "eDP",
168             Interface::Virtual => "Virtual",
169             Interface::DSI => "DSI",
170             Interface::DPI => "DPI",
171             Interface::Writeback => "Writeback",
172             Interface::SPI => "SPI",
173             Interface::USB => "USB",
174         }
175     }
176 }
177 
178 impl From<u32> for Interface {
from(n: u32) -> Self179     fn from(n: u32) -> Self {
180         match n {
181             ffi::DRM_MODE_CONNECTOR_Unknown => Interface::Unknown,
182             ffi::DRM_MODE_CONNECTOR_VGA => Interface::VGA,
183             ffi::DRM_MODE_CONNECTOR_DVII => Interface::DVII,
184             ffi::DRM_MODE_CONNECTOR_DVID => Interface::DVID,
185             ffi::DRM_MODE_CONNECTOR_DVIA => Interface::DVIA,
186             ffi::DRM_MODE_CONNECTOR_Composite => Interface::Composite,
187             ffi::DRM_MODE_CONNECTOR_SVIDEO => Interface::SVideo,
188             ffi::DRM_MODE_CONNECTOR_LVDS => Interface::LVDS,
189             ffi::DRM_MODE_CONNECTOR_Component => Interface::Component,
190             ffi::DRM_MODE_CONNECTOR_9PinDIN => Interface::NinePinDIN,
191             ffi::DRM_MODE_CONNECTOR_DisplayPort => Interface::DisplayPort,
192             ffi::DRM_MODE_CONNECTOR_HDMIA => Interface::HDMIA,
193             ffi::DRM_MODE_CONNECTOR_HDMIB => Interface::HDMIB,
194             ffi::DRM_MODE_CONNECTOR_TV => Interface::TV,
195             ffi::DRM_MODE_CONNECTOR_eDP => Interface::EmbeddedDisplayPort,
196             ffi::DRM_MODE_CONNECTOR_VIRTUAL => Interface::Virtual,
197             ffi::DRM_MODE_CONNECTOR_DSI => Interface::DSI,
198             ffi::DRM_MODE_CONNECTOR_DPI => Interface::DPI,
199             ffi::DRM_MODE_CONNECTOR_WRITEBACK => Interface::Writeback,
200             ffi::DRM_MODE_CONNECTOR_SPI => Interface::SPI,
201             ffi::DRM_MODE_CONNECTOR_USB => Interface::USB,
202             _ => Interface::Unknown,
203         }
204     }
205 }
206 
207 impl From<Interface> for u32 {
from(interface: Interface) -> Self208     fn from(interface: Interface) -> Self {
209         match interface {
210             Interface::Unknown => ffi::DRM_MODE_CONNECTOR_Unknown,
211             Interface::VGA => ffi::DRM_MODE_CONNECTOR_VGA,
212             Interface::DVII => ffi::DRM_MODE_CONNECTOR_DVII,
213             Interface::DVID => ffi::DRM_MODE_CONNECTOR_DVID,
214             Interface::DVIA => ffi::DRM_MODE_CONNECTOR_DVIA,
215             Interface::Composite => ffi::DRM_MODE_CONNECTOR_Composite,
216             Interface::SVideo => ffi::DRM_MODE_CONNECTOR_SVIDEO,
217             Interface::LVDS => ffi::DRM_MODE_CONNECTOR_LVDS,
218             Interface::Component => ffi::DRM_MODE_CONNECTOR_Component,
219             Interface::NinePinDIN => ffi::DRM_MODE_CONNECTOR_9PinDIN,
220             Interface::DisplayPort => ffi::DRM_MODE_CONNECTOR_DisplayPort,
221             Interface::HDMIA => ffi::DRM_MODE_CONNECTOR_HDMIA,
222             Interface::HDMIB => ffi::DRM_MODE_CONNECTOR_HDMIB,
223             Interface::TV => ffi::DRM_MODE_CONNECTOR_TV,
224             Interface::EmbeddedDisplayPort => ffi::DRM_MODE_CONNECTOR_eDP,
225             Interface::Virtual => ffi::DRM_MODE_CONNECTOR_VIRTUAL,
226             Interface::DSI => ffi::DRM_MODE_CONNECTOR_DSI,
227             Interface::DPI => ffi::DRM_MODE_CONNECTOR_DPI,
228             Interface::Writeback => ffi::DRM_MODE_CONNECTOR_WRITEBACK,
229             Interface::SPI => ffi::DRM_MODE_CONNECTOR_SPI,
230             Interface::USB => ffi::DRM_MODE_CONNECTOR_USB,
231         }
232     }
233 }
234 
235 /// The state of a connector.
236 #[allow(missing_docs)]
237 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
238 pub enum State {
239     Connected,
240     Disconnected,
241     Unknown,
242 }
243 
244 impl From<u32> for State {
from(n: u32) -> Self245     fn from(n: u32) -> Self {
246         // These variables are not defined in drm_mode.h for some reason.
247         // They were copied from libdrm's xf86DrmMode.h
248         match n {
249             1 => State::Connected,
250             2 => State::Disconnected,
251             _ => State::Unknown,
252         }
253     }
254 }
255 
256 impl From<State> for u32 {
from(state: State) -> Self257     fn from(state: State) -> Self {
258         // These variables are not defined in drm_mode.h for some reason.
259         // They were copied from libdrm's xf86DrmMode.h
260         match state {
261             State::Connected => 1,
262             State::Disconnected => 2,
263             State::Unknown => 3,
264         }
265     }
266 }
267 
268 /// Subpixel order of the connected sink
269 #[non_exhaustive]
270 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
271 pub enum SubPixel {
272     /// Unknown geometry
273     Unknown,
274     /// Horizontal RGB
275     HorizontalRgb,
276     /// Horizontal BGR
277     HorizontalBgr,
278     /// Vertical RGB
279     VerticalRgb,
280     /// Vertical BGR
281     VerticalBgr,
282     /// No geometry
283     None,
284     /// Encountered value not supported by drm-rs
285     NotImplemented,
286 }
287 
288 impl SubPixel {
from_raw(n: u32) -> Self289     pub(super) fn from_raw(n: u32) -> Self {
290         // These values are not defined in drm_mode.h
291         // They were copied from linux's drm_connector.h
292         // Don't mistake those for ones used in xf86DrmMode.h (libdrm offsets those by 1)
293         match n {
294             0 => Self::Unknown,
295             1 => Self::HorizontalRgb,
296             2 => Self::HorizontalBgr,
297             3 => Self::VerticalRgb,
298             4 => Self::VerticalBgr,
299             5 => Self::None,
300             _ => Self::NotImplemented,
301         }
302     }
303 }
304