xref: /aosp_15_r20/external/libkmsxx/kms++/src/connector.cpp (revision f0687c8a10b3e371dbe09214db6664e37c283cca)
1*f0687c8aSRaman Tenneti #include <cstdio>
2*f0687c8aSRaman Tenneti #include <iostream>
3*f0687c8aSRaman Tenneti #include <unistd.h>
4*f0687c8aSRaman Tenneti #include <fcntl.h>
5*f0687c8aSRaman Tenneti #include <cassert>
6*f0687c8aSRaman Tenneti #include <cmath>
7*f0687c8aSRaman Tenneti 
8*f0687c8aSRaman Tenneti #include <kms++/kms++.h>
9*f0687c8aSRaman Tenneti #include "helpers.h"
10*f0687c8aSRaman Tenneti 
11*f0687c8aSRaman Tenneti using namespace std;
12*f0687c8aSRaman Tenneti 
13*f0687c8aSRaman Tenneti namespace kms
14*f0687c8aSRaman Tenneti {
15*f0687c8aSRaman Tenneti #ifndef DRM_MODE_CONNECTOR_DPI
16*f0687c8aSRaman Tenneti #define DRM_MODE_CONNECTOR_DPI 17
17*f0687c8aSRaman Tenneti #endif
18*f0687c8aSRaman Tenneti 
19*f0687c8aSRaman Tenneti static const map<int, string> connector_names = {
20*f0687c8aSRaman Tenneti 	{ DRM_MODE_CONNECTOR_Unknown, "Unknown" },
21*f0687c8aSRaman Tenneti 	{ DRM_MODE_CONNECTOR_VGA, "VGA" },
22*f0687c8aSRaman Tenneti 	{ DRM_MODE_CONNECTOR_DVII, "DVI-I" },
23*f0687c8aSRaman Tenneti 	{ DRM_MODE_CONNECTOR_DVID, "DVI-D" },
24*f0687c8aSRaman Tenneti 	{ DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
25*f0687c8aSRaman Tenneti 	{ DRM_MODE_CONNECTOR_Composite, "Composite" },
26*f0687c8aSRaman Tenneti 	{ DRM_MODE_CONNECTOR_SVIDEO, "S-Video" },
27*f0687c8aSRaman Tenneti 	{ DRM_MODE_CONNECTOR_LVDS, "LVDS" },
28*f0687c8aSRaman Tenneti 	{ DRM_MODE_CONNECTOR_Component, "Component" },
29*f0687c8aSRaman Tenneti 	{ DRM_MODE_CONNECTOR_9PinDIN, "9-Pin-DIN" },
30*f0687c8aSRaman Tenneti 	{ DRM_MODE_CONNECTOR_DisplayPort, "DP" },
31*f0687c8aSRaman Tenneti 	{ DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
32*f0687c8aSRaman Tenneti 	{ DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
33*f0687c8aSRaman Tenneti 	{ DRM_MODE_CONNECTOR_TV, "TV" },
34*f0687c8aSRaman Tenneti 	{ DRM_MODE_CONNECTOR_eDP, "eDP" },
35*f0687c8aSRaman Tenneti 	{ DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" },
36*f0687c8aSRaman Tenneti 	{ DRM_MODE_CONNECTOR_DSI, "DSI" },
37*f0687c8aSRaman Tenneti 	{ DRM_MODE_CONNECTOR_DPI, "DPI" },
38*f0687c8aSRaman Tenneti };
39*f0687c8aSRaman Tenneti 
40*f0687c8aSRaman Tenneti static const map<int, string> connection_str = {
41*f0687c8aSRaman Tenneti 	{ 0, "<unknown>" },
42*f0687c8aSRaman Tenneti 	{ DRM_MODE_CONNECTED, "Connected" },
43*f0687c8aSRaman Tenneti 	{ DRM_MODE_DISCONNECTED, "Disconnected" },
44*f0687c8aSRaman Tenneti 	{ DRM_MODE_UNKNOWNCONNECTION, "Unknown" },
45*f0687c8aSRaman Tenneti };
46*f0687c8aSRaman Tenneti 
47*f0687c8aSRaman Tenneti static const map<int, string> subpix_str = {
48*f0687c8aSRaman Tenneti #define DEF_SUBPIX(c)                     \
49*f0687c8aSRaman Tenneti 	{                                 \
50*f0687c8aSRaman Tenneti 		DRM_MODE_SUBPIXEL_##c, #c \
51*f0687c8aSRaman Tenneti 	}
52*f0687c8aSRaman Tenneti 	DEF_SUBPIX(UNKNOWN),
53*f0687c8aSRaman Tenneti 	DEF_SUBPIX(HORIZONTAL_RGB),
54*f0687c8aSRaman Tenneti 	DEF_SUBPIX(HORIZONTAL_BGR),
55*f0687c8aSRaman Tenneti 	DEF_SUBPIX(VERTICAL_RGB),
56*f0687c8aSRaman Tenneti 	DEF_SUBPIX(VERTICAL_BGR),
57*f0687c8aSRaman Tenneti 	DEF_SUBPIX(NONE),
58*f0687c8aSRaman Tenneti #undef DEF_SUBPIX
59*f0687c8aSRaman Tenneti };
60*f0687c8aSRaman Tenneti 
61*f0687c8aSRaman Tenneti struct ConnectorPriv {
62*f0687c8aSRaman Tenneti 	drmModeConnectorPtr drm_connector;
63*f0687c8aSRaman Tenneti };
64*f0687c8aSRaman Tenneti 
Connector(Card & card,uint32_t id,uint32_t idx)65*f0687c8aSRaman Tenneti Connector::Connector(Card& card, uint32_t id, uint32_t idx)
66*f0687c8aSRaman Tenneti 	: DrmPropObject(card, id, DRM_MODE_OBJECT_CONNECTOR, idx)
67*f0687c8aSRaman Tenneti {
68*f0687c8aSRaman Tenneti 	m_priv = new ConnectorPriv();
69*f0687c8aSRaman Tenneti 
70*f0687c8aSRaman Tenneti 	m_priv->drm_connector = drmModeGetConnector(this->card().fd(), this->id());
71*f0687c8aSRaman Tenneti 	assert(m_priv->drm_connector);
72*f0687c8aSRaman Tenneti 
73*f0687c8aSRaman Tenneti 	// XXX drmModeGetConnector() does forced probe, which seems to change (at least) EDID blob id.
74*f0687c8aSRaman Tenneti 	// XXX So refresh the props again here.
75*f0687c8aSRaman Tenneti 	refresh_props();
76*f0687c8aSRaman Tenneti 
77*f0687c8aSRaman Tenneti 	const auto& name = connector_names.at(m_priv->drm_connector->connector_type);
78*f0687c8aSRaman Tenneti 	m_fullname = name + "-" + to_string(m_priv->drm_connector->connector_type_id);
79*f0687c8aSRaman Tenneti }
80*f0687c8aSRaman Tenneti 
~Connector()81*f0687c8aSRaman Tenneti Connector::~Connector()
82*f0687c8aSRaman Tenneti {
83*f0687c8aSRaman Tenneti 	drmModeFreeConnector(m_priv->drm_connector);
84*f0687c8aSRaman Tenneti 	delete m_priv;
85*f0687c8aSRaman Tenneti }
86*f0687c8aSRaman Tenneti 
refresh()87*f0687c8aSRaman Tenneti void Connector::refresh()
88*f0687c8aSRaman Tenneti {
89*f0687c8aSRaman Tenneti 	drmModeFreeConnector(m_priv->drm_connector);
90*f0687c8aSRaman Tenneti 
91*f0687c8aSRaman Tenneti 	m_priv->drm_connector = drmModeGetConnector(this->card().fd(), this->id());
92*f0687c8aSRaman Tenneti 	assert(m_priv->drm_connector);
93*f0687c8aSRaman Tenneti 
94*f0687c8aSRaman Tenneti 	// XXX drmModeGetConnector() does forced probe, which seems to change (at least) EDID blob id.
95*f0687c8aSRaman Tenneti 	// XXX So refresh the props again here.
96*f0687c8aSRaman Tenneti 	refresh_props();
97*f0687c8aSRaman Tenneti 
98*f0687c8aSRaman Tenneti 	const auto& name = connector_names.at(m_priv->drm_connector->connector_type);
99*f0687c8aSRaman Tenneti 	m_fullname = name + "-" + to_string(m_priv->drm_connector->connector_type_id);
100*f0687c8aSRaman Tenneti }
101*f0687c8aSRaman Tenneti 
setup()102*f0687c8aSRaman Tenneti void Connector::setup()
103*f0687c8aSRaman Tenneti {
104*f0687c8aSRaman Tenneti 	if (m_priv->drm_connector->encoder_id != 0)
105*f0687c8aSRaman Tenneti 		m_current_encoder = card().get_encoder(m_priv->drm_connector->encoder_id);
106*f0687c8aSRaman Tenneti 	else
107*f0687c8aSRaman Tenneti 		m_current_encoder = 0;
108*f0687c8aSRaman Tenneti 
109*f0687c8aSRaman Tenneti 	if (m_current_encoder)
110*f0687c8aSRaman Tenneti 		m_saved_crtc = m_current_encoder->get_crtc();
111*f0687c8aSRaman Tenneti 	else
112*f0687c8aSRaman Tenneti 		m_saved_crtc = 0;
113*f0687c8aSRaman Tenneti }
114*f0687c8aSRaman Tenneti 
restore_mode()115*f0687c8aSRaman Tenneti void Connector::restore_mode()
116*f0687c8aSRaman Tenneti {
117*f0687c8aSRaman Tenneti 	if (m_saved_crtc)
118*f0687c8aSRaman Tenneti 		m_saved_crtc->restore_mode(this);
119*f0687c8aSRaman Tenneti }
120*f0687c8aSRaman Tenneti 
get_default_mode() const121*f0687c8aSRaman Tenneti Videomode Connector::get_default_mode() const
122*f0687c8aSRaman Tenneti {
123*f0687c8aSRaman Tenneti 	if (m_priv->drm_connector->count_modes == 0)
124*f0687c8aSRaman Tenneti 		return Videomode();
125*f0687c8aSRaman Tenneti 
126*f0687c8aSRaman Tenneti 	drmModeModeInfo drmmode = m_priv->drm_connector->modes[0];
127*f0687c8aSRaman Tenneti 
128*f0687c8aSRaman Tenneti 	return drm_mode_to_video_mode(drmmode);
129*f0687c8aSRaman Tenneti }
130*f0687c8aSRaman Tenneti 
get_mode(const string & mode) const131*f0687c8aSRaman Tenneti Videomode Connector::get_mode(const string& mode) const
132*f0687c8aSRaman Tenneti {
133*f0687c8aSRaman Tenneti 	auto c = m_priv->drm_connector;
134*f0687c8aSRaman Tenneti 
135*f0687c8aSRaman Tenneti 	size_t idx = mode.find('@');
136*f0687c8aSRaman Tenneti 
137*f0687c8aSRaman Tenneti 	string name = idx == string::npos ? mode : mode.substr(0, idx);
138*f0687c8aSRaman Tenneti 	float vrefresh = idx == string::npos ? 0.0 : stod(mode.substr(idx + 1));
139*f0687c8aSRaman Tenneti 
140*f0687c8aSRaman Tenneti 	for (int i = 0; i < c->count_modes; i++) {
141*f0687c8aSRaman Tenneti 		Videomode m = drm_mode_to_video_mode(c->modes[i]);
142*f0687c8aSRaman Tenneti 
143*f0687c8aSRaman Tenneti 		if (m.name != name)
144*f0687c8aSRaman Tenneti 			continue;
145*f0687c8aSRaman Tenneti 
146*f0687c8aSRaman Tenneti 		if (vrefresh && vrefresh != m.calculated_vrefresh())
147*f0687c8aSRaman Tenneti 			continue;
148*f0687c8aSRaman Tenneti 
149*f0687c8aSRaman Tenneti 		return m;
150*f0687c8aSRaman Tenneti 	}
151*f0687c8aSRaman Tenneti 
152*f0687c8aSRaman Tenneti 	throw invalid_argument(mode + ": mode not found");
153*f0687c8aSRaman Tenneti }
154*f0687c8aSRaman Tenneti 
get_mode(unsigned xres,unsigned yres,float vrefresh,bool ilace) const155*f0687c8aSRaman Tenneti Videomode Connector::get_mode(unsigned xres, unsigned yres, float vrefresh, bool ilace) const
156*f0687c8aSRaman Tenneti {
157*f0687c8aSRaman Tenneti 	auto c = m_priv->drm_connector;
158*f0687c8aSRaman Tenneti 
159*f0687c8aSRaman Tenneti 	for (int i = 0; i < c->count_modes; i++) {
160*f0687c8aSRaman Tenneti 		Videomode m = drm_mode_to_video_mode(c->modes[i]);
161*f0687c8aSRaman Tenneti 
162*f0687c8aSRaman Tenneti 		if (m.hdisplay != xres || m.vdisplay != yres)
163*f0687c8aSRaman Tenneti 			continue;
164*f0687c8aSRaman Tenneti 
165*f0687c8aSRaman Tenneti 		if (ilace != m.interlace())
166*f0687c8aSRaman Tenneti 			continue;
167*f0687c8aSRaman Tenneti 
168*f0687c8aSRaman Tenneti 		if (vrefresh && vrefresh != m.calculated_vrefresh())
169*f0687c8aSRaman Tenneti 			continue;
170*f0687c8aSRaman Tenneti 
171*f0687c8aSRaman Tenneti 		return m;
172*f0687c8aSRaman Tenneti 	}
173*f0687c8aSRaman Tenneti 
174*f0687c8aSRaman Tenneti 	// If not found, do another round using rounded vrefresh
175*f0687c8aSRaman Tenneti 
176*f0687c8aSRaman Tenneti 	for (int i = 0; i < c->count_modes; i++) {
177*f0687c8aSRaman Tenneti 		Videomode m = drm_mode_to_video_mode(c->modes[i]);
178*f0687c8aSRaman Tenneti 
179*f0687c8aSRaman Tenneti 		if (m.hdisplay != xres || m.vdisplay != yres)
180*f0687c8aSRaman Tenneti 			continue;
181*f0687c8aSRaman Tenneti 
182*f0687c8aSRaman Tenneti 		if (ilace != m.interlace())
183*f0687c8aSRaman Tenneti 			continue;
184*f0687c8aSRaman Tenneti 
185*f0687c8aSRaman Tenneti 		if (vrefresh && vrefresh != roundf(m.calculated_vrefresh()))
186*f0687c8aSRaman Tenneti 			continue;
187*f0687c8aSRaman Tenneti 
188*f0687c8aSRaman Tenneti 		return m;
189*f0687c8aSRaman Tenneti 	}
190*f0687c8aSRaman Tenneti 
191*f0687c8aSRaman Tenneti 	throw invalid_argument("mode not found");
192*f0687c8aSRaman Tenneti }
193*f0687c8aSRaman Tenneti 
connected() const194*f0687c8aSRaman Tenneti bool Connector::connected() const
195*f0687c8aSRaman Tenneti {
196*f0687c8aSRaman Tenneti 	return m_priv->drm_connector->connection == DRM_MODE_CONNECTED ||
197*f0687c8aSRaman Tenneti 	       m_priv->drm_connector->connection == DRM_MODE_UNKNOWNCONNECTION;
198*f0687c8aSRaman Tenneti }
199*f0687c8aSRaman Tenneti 
connector_status() const200*f0687c8aSRaman Tenneti ConnectorStatus Connector::connector_status() const
201*f0687c8aSRaman Tenneti {
202*f0687c8aSRaman Tenneti 	switch (m_priv->drm_connector->connection) {
203*f0687c8aSRaman Tenneti 	case DRM_MODE_CONNECTED:
204*f0687c8aSRaman Tenneti 		return ConnectorStatus::Connected;
205*f0687c8aSRaman Tenneti 	case DRM_MODE_DISCONNECTED:
206*f0687c8aSRaman Tenneti 		return ConnectorStatus::Disconnected;
207*f0687c8aSRaman Tenneti 	default:
208*f0687c8aSRaman Tenneti 		return ConnectorStatus::Unknown;
209*f0687c8aSRaman Tenneti 	}
210*f0687c8aSRaman Tenneti }
211*f0687c8aSRaman Tenneti 
get_possible_crtcs() const212*f0687c8aSRaman Tenneti vector<Crtc*> Connector::get_possible_crtcs() const
213*f0687c8aSRaman Tenneti {
214*f0687c8aSRaman Tenneti 	vector<Crtc*> crtcs;
215*f0687c8aSRaman Tenneti 
216*f0687c8aSRaman Tenneti 	for (int i = 0; i < m_priv->drm_connector->count_encoders; ++i) {
217*f0687c8aSRaman Tenneti 		auto enc = card().get_encoder(m_priv->drm_connector->encoders[i]);
218*f0687c8aSRaman Tenneti 
219*f0687c8aSRaman Tenneti 		auto l = enc->get_possible_crtcs();
220*f0687c8aSRaman Tenneti 
221*f0687c8aSRaman Tenneti 		crtcs.insert(crtcs.end(), l.begin(), l.end());
222*f0687c8aSRaman Tenneti 	}
223*f0687c8aSRaman Tenneti 
224*f0687c8aSRaman Tenneti 	return crtcs;
225*f0687c8aSRaman Tenneti }
226*f0687c8aSRaman Tenneti 
get_current_crtc() const227*f0687c8aSRaman Tenneti Crtc* Connector::get_current_crtc() const
228*f0687c8aSRaman Tenneti {
229*f0687c8aSRaman Tenneti 	if (m_current_encoder)
230*f0687c8aSRaman Tenneti 		return m_current_encoder->get_crtc();
231*f0687c8aSRaman Tenneti 	else
232*f0687c8aSRaman Tenneti 		return 0;
233*f0687c8aSRaman Tenneti }
234*f0687c8aSRaman Tenneti 
connector_type() const235*f0687c8aSRaman Tenneti uint32_t Connector::connector_type() const
236*f0687c8aSRaman Tenneti {
237*f0687c8aSRaman Tenneti 	return m_priv->drm_connector->connector_type;
238*f0687c8aSRaman Tenneti }
239*f0687c8aSRaman Tenneti 
connector_type_id() const240*f0687c8aSRaman Tenneti uint32_t Connector::connector_type_id() const
241*f0687c8aSRaman Tenneti {
242*f0687c8aSRaman Tenneti 	return m_priv->drm_connector->connector_type_id;
243*f0687c8aSRaman Tenneti }
244*f0687c8aSRaman Tenneti 
mmWidth() const245*f0687c8aSRaman Tenneti uint32_t Connector::mmWidth() const
246*f0687c8aSRaman Tenneti {
247*f0687c8aSRaman Tenneti 	return m_priv->drm_connector->mmWidth;
248*f0687c8aSRaman Tenneti }
249*f0687c8aSRaman Tenneti 
mmHeight() const250*f0687c8aSRaman Tenneti uint32_t Connector::mmHeight() const
251*f0687c8aSRaman Tenneti {
252*f0687c8aSRaman Tenneti 	return m_priv->drm_connector->mmHeight;
253*f0687c8aSRaman Tenneti }
254*f0687c8aSRaman Tenneti 
subpixel() const255*f0687c8aSRaman Tenneti uint32_t Connector::subpixel() const
256*f0687c8aSRaman Tenneti {
257*f0687c8aSRaman Tenneti 	return m_priv->drm_connector->subpixel;
258*f0687c8aSRaman Tenneti }
259*f0687c8aSRaman Tenneti 
subpixel_str() const260*f0687c8aSRaman Tenneti const string& Connector::subpixel_str() const
261*f0687c8aSRaman Tenneti {
262*f0687c8aSRaman Tenneti 	return subpix_str.at(subpixel());
263*f0687c8aSRaman Tenneti }
264*f0687c8aSRaman Tenneti 
get_modes() const265*f0687c8aSRaman Tenneti std::vector<Videomode> Connector::get_modes() const
266*f0687c8aSRaman Tenneti {
267*f0687c8aSRaman Tenneti 	vector<Videomode> modes;
268*f0687c8aSRaman Tenneti 
269*f0687c8aSRaman Tenneti 	for (int i = 0; i < m_priv->drm_connector->count_modes; i++)
270*f0687c8aSRaman Tenneti 		modes.push_back(drm_mode_to_video_mode(
271*f0687c8aSRaman Tenneti 			m_priv->drm_connector->modes[i]));
272*f0687c8aSRaman Tenneti 
273*f0687c8aSRaman Tenneti 	return modes;
274*f0687c8aSRaman Tenneti }
275*f0687c8aSRaman Tenneti 
get_encoders() const276*f0687c8aSRaman Tenneti std::vector<Encoder*> Connector::get_encoders() const
277*f0687c8aSRaman Tenneti {
278*f0687c8aSRaman Tenneti 	vector<Encoder*> encoders;
279*f0687c8aSRaman Tenneti 
280*f0687c8aSRaman Tenneti 	for (int i = 0; i < m_priv->drm_connector->count_encoders; i++) {
281*f0687c8aSRaman Tenneti 		auto enc = card().get_encoder(m_priv->drm_connector->encoders[i]);
282*f0687c8aSRaman Tenneti 		encoders.push_back(enc);
283*f0687c8aSRaman Tenneti 	}
284*f0687c8aSRaman Tenneti 	return encoders;
285*f0687c8aSRaman Tenneti }
286*f0687c8aSRaman Tenneti 
287*f0687c8aSRaman Tenneti } // namespace kms
288