48c581564621640b951e5995e6dd3539da534621
1 #include <stdio.h>
2 #include <iostream>
3 #include <unistd.h>
4 #include <fcntl.h>
5 #include <cassert>
6 #include <cmath>
8 #include <kms++/kms++.h>
9 #include "helpers.h"
11 using namespace std;
13 namespace kms
14 {
17 static const map<int, string> connector_names = {
18 { DRM_MODE_CONNECTOR_Unknown, "Unknown" },
19 { DRM_MODE_CONNECTOR_VGA, "VGA" },
20 { DRM_MODE_CONNECTOR_DVII, "DVI-I" },
21 { DRM_MODE_CONNECTOR_DVID, "DVI-D" },
22 { DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
23 { DRM_MODE_CONNECTOR_Composite, "Composite" },
24 { DRM_MODE_CONNECTOR_SVIDEO, "S-Video" },
25 { DRM_MODE_CONNECTOR_LVDS, "LVDS" },
26 { DRM_MODE_CONNECTOR_Component, "Component" },
27 { DRM_MODE_CONNECTOR_9PinDIN, "9-Pin-DIN" },
28 { DRM_MODE_CONNECTOR_DisplayPort, "DP" },
29 { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
30 { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
31 { DRM_MODE_CONNECTOR_TV, "TV" },
32 { DRM_MODE_CONNECTOR_eDP, "eDP" },
33 { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" },
34 { DRM_MODE_CONNECTOR_DSI, "DSI" },
35 };
37 static const map<int, string> connection_str = {
38 { 0, "<unknown>" },
39 { DRM_MODE_CONNECTED, "Connected" },
40 { DRM_MODE_DISCONNECTED, "Disconnected" },
41 { DRM_MODE_UNKNOWNCONNECTION, "Unknown" },
42 };
44 static const map<int, string> subpix_str = {
45 #define DEF_SUBPIX(c) { DRM_MODE_SUBPIXEL_##c, #c }
46 DEF_SUBPIX(UNKNOWN),
47 DEF_SUBPIX(HORIZONTAL_RGB),
48 DEF_SUBPIX(HORIZONTAL_BGR),
49 DEF_SUBPIX(VERTICAL_RGB),
50 DEF_SUBPIX(VERTICAL_BGR),
51 DEF_SUBPIX(NONE),
52 #undef DEF_SUBPIX
53 };
55 struct ConnectorPriv
56 {
57 drmModeConnectorPtr drm_connector;
58 };
60 Connector::Connector(Card &card, uint32_t id, uint32_t idx)
61 :DrmPropObject(card, id, DRM_MODE_OBJECT_CONNECTOR, idx)
62 {
63 m_priv = new ConnectorPriv();
65 m_priv->drm_connector = drmModeGetConnector(this->card().fd(), this->id());
66 assert(m_priv->drm_connector);
68 // XXX drmModeGetConnector() does forced probe, which seems to change (at least) EDID blob id.
69 // XXX So refresh the props again here.
70 refresh_props();
72 const auto& name = connector_names.at(m_priv->drm_connector->connector_type);
73 m_fullname = name + "-" + to_string(m_priv->drm_connector->connector_type_id);
74 }
76 Connector::~Connector()
77 {
78 drmModeFreeConnector(m_priv->drm_connector);
79 delete m_priv;
80 }
82 void Connector::refresh()
83 {
84 drmModeFreeConnector(m_priv->drm_connector);
86 m_priv->drm_connector = drmModeGetConnector(this->card().fd(), this->id());
87 assert(m_priv->drm_connector);
89 // XXX drmModeGetConnector() does forced probe, which seems to change (at least) EDID blob id.
90 // XXX So refresh the props again here.
91 refresh_props();
93 const auto& name = connector_names.at(m_priv->drm_connector->connector_type);
94 m_fullname = name + "-" + to_string(m_priv->drm_connector->connector_type_id);
95 }
97 void Connector::setup()
98 {
99 if (m_priv->drm_connector->encoder_id != 0)
100 m_current_encoder = card().get_encoder(m_priv->drm_connector->encoder_id);
101 else
102 m_current_encoder = 0;
104 if (m_current_encoder)
105 m_saved_crtc = m_current_encoder->get_crtc();
106 else
107 m_saved_crtc = 0;
108 }
110 void Connector::restore_mode()
111 {
112 if (m_saved_crtc)
113 m_saved_crtc->restore_mode(this);
114 }
116 Videomode Connector::get_default_mode() const
117 {
118 if (m_priv->drm_connector->count_modes == 0)
119 throw invalid_argument("no modes available\n");
120 drmModeModeInfo drmmode = m_priv->drm_connector->modes[0];
122 return drm_mode_to_video_mode(drmmode);
123 }
125 Videomode Connector::get_mode(const string& mode) const
126 {
127 auto c = m_priv->drm_connector;
129 for (int i = 0; i < c->count_modes; i++)
130 if (mode == c->modes[i].name)
131 return drm_mode_to_video_mode(c->modes[i]);
133 throw invalid_argument(mode + ": mode not found");
134 }
136 Videomode Connector::get_mode(unsigned xres, unsigned yres, float vrefresh, bool ilace) const
137 {
138 auto c = m_priv->drm_connector;
140 for (int i = 0; i < c->count_modes; i++) {
141 Videomode m = drm_mode_to_video_mode(c->modes[i]);
143 if (m.hdisplay != xres || m.vdisplay != yres)
144 continue;
146 if (ilace != m.interlace())
147 continue;
149 if (vrefresh && vrefresh != m.calculated_vrefresh())
150 continue;
152 return m;
153 }
155 // If not found, do another round using rounded vrefresh
157 for (int i = 0; i < c->count_modes; i++) {
158 Videomode m = drm_mode_to_video_mode(c->modes[i]);
160 if (m.hdisplay != xres || m.vdisplay != yres)
161 continue;
163 if (ilace != m.interlace())
164 continue;
166 if (vrefresh && vrefresh != roundf(m.calculated_vrefresh()))
167 continue;
169 return m;
170 }
172 throw invalid_argument("mode not found");
173 }
175 bool Connector::connected() const
176 {
177 return m_priv->drm_connector->connection == DRM_MODE_CONNECTED ||
178 m_priv->drm_connector->connection == DRM_MODE_UNKNOWNCONNECTION;
179 }
181 vector<Crtc*> Connector::get_possible_crtcs() const
182 {
183 vector<Crtc*> crtcs;
185 for (int i = 0; i < m_priv->drm_connector->count_encoders; ++i) {
186 auto enc = card().get_encoder(m_priv->drm_connector->encoders[i]);
188 auto l = enc->get_possible_crtcs();
190 crtcs.insert(crtcs.end(), l.begin(), l.end());
191 }
193 return crtcs;
194 }
196 Crtc* Connector::get_current_crtc() const
197 {
198 if (m_current_encoder)
199 return m_current_encoder->get_crtc();
200 else
201 return 0;
202 }
204 uint32_t Connector::connector_type() const
205 {
206 return m_priv->drm_connector->connector_type;
207 }
209 uint32_t Connector::connector_type_id() const
210 {
211 return m_priv->drm_connector->connector_type_id;
212 }
214 uint32_t Connector::mmWidth() const
215 {
216 return m_priv->drm_connector->mmWidth;
217 }
219 uint32_t Connector::mmHeight() const
220 {
221 return m_priv->drm_connector->mmHeight;
222 }
224 uint32_t Connector::subpixel() const
225 {
226 return m_priv->drm_connector->subpixel;
227 }
229 const string& Connector::subpixel_str() const
230 {
231 return subpix_str.at(subpixel());
232 }
234 std::vector<Videomode> Connector::get_modes() const
235 {
236 vector<Videomode> modes;
238 for (int i = 0; i < m_priv->drm_connector->count_modes; i++)
239 modes.push_back(drm_mode_to_video_mode(
240 m_priv->drm_connector->modes[i]));
242 return modes;
243 }
245 std::vector<Encoder*> Connector::get_encoders() const
246 {
247 vector<Encoder*> encoders;
249 for (int i = 0; i < m_priv->drm_connector->count_encoders; i++) {
250 auto enc = card().get_encoder(m_priv->drm_connector->encoders[i]);
251 encoders.push_back(enc);
252 }
253 return encoders;
254 }
256 }