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