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 {
16 #ifndef DRM_MODE_CONNECTOR_DPI
17 #define DRM_MODE_CONNECTOR_DPI 17
18 #endif
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 };
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 };
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 };
59 struct ConnectorPriv
60 {
61 drmModeConnectorPtr drm_connector;
62 };
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();
69 m_priv->drm_connector = drmModeGetConnector(this->card().fd(), this->id());
70 assert(m_priv->drm_connector);
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();
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 }
80 Connector::~Connector()
81 {
82 drmModeFreeConnector(m_priv->drm_connector);
83 delete m_priv;
84 }
86 void Connector::refresh()
87 {
88 drmModeFreeConnector(m_priv->drm_connector);
90 m_priv->drm_connector = drmModeGetConnector(this->card().fd(), this->id());
91 assert(m_priv->drm_connector);
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();
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 }
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;
108 if (m_current_encoder)
109 m_saved_crtc = m_current_encoder->get_crtc();
110 else
111 m_saved_crtc = 0;
112 }
114 void Connector::restore_mode()
115 {
116 if (m_saved_crtc)
117 m_saved_crtc->restore_mode(this);
118 }
120 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];
126 return drm_mode_to_video_mode(drmmode);
127 }
129 Videomode Connector::get_mode(const string& mode) const
130 {
131 auto c = m_priv->drm_connector;
133 for (int i = 0; i < c->count_modes; i++)
134 if (mode == c->modes[i].name)
135 return drm_mode_to_video_mode(c->modes[i]);
137 throw invalid_argument(mode + ": mode not found");
138 }
140 Videomode Connector::get_mode(unsigned xres, unsigned yres, float vrefresh, bool ilace) const
141 {
142 auto c = m_priv->drm_connector;
144 for (int i = 0; i < c->count_modes; i++) {
145 Videomode m = drm_mode_to_video_mode(c->modes[i]);
147 if (m.hdisplay != xres || m.vdisplay != yres)
148 continue;
150 if (ilace != m.interlace())
151 continue;
153 if (vrefresh && vrefresh != m.calculated_vrefresh())
154 continue;
156 return m;
157 }
159 // If not found, do another round using rounded vrefresh
161 for (int i = 0; i < c->count_modes; i++) {
162 Videomode m = drm_mode_to_video_mode(c->modes[i]);
164 if (m.hdisplay != xres || m.vdisplay != yres)
165 continue;
167 if (ilace != m.interlace())
168 continue;
170 if (vrefresh && vrefresh != roundf(m.calculated_vrefresh()))
171 continue;
173 return m;
174 }
176 throw invalid_argument("mode not found");
177 }
179 bool Connector::connected() const
180 {
181 return m_priv->drm_connector->connection == DRM_MODE_CONNECTED ||
182 m_priv->drm_connector->connection == DRM_MODE_UNKNOWNCONNECTION;
183 }
185 vector<Crtc*> Connector::get_possible_crtcs() const
186 {
187 vector<Crtc*> crtcs;
189 for (int i = 0; i < m_priv->drm_connector->count_encoders; ++i) {
190 auto enc = card().get_encoder(m_priv->drm_connector->encoders[i]);
192 auto l = enc->get_possible_crtcs();
194 crtcs.insert(crtcs.end(), l.begin(), l.end());
195 }
197 return crtcs;
198 }
200 Crtc* Connector::get_current_crtc() const
201 {
202 if (m_current_encoder)
203 return m_current_encoder->get_crtc();
204 else
205 return 0;
206 }
208 uint32_t Connector::connector_type() const
209 {
210 return m_priv->drm_connector->connector_type;
211 }
213 uint32_t Connector::connector_type_id() const
214 {
215 return m_priv->drm_connector->connector_type_id;
216 }
218 uint32_t Connector::mmWidth() const
219 {
220 return m_priv->drm_connector->mmWidth;
221 }
223 uint32_t Connector::mmHeight() const
224 {
225 return m_priv->drm_connector->mmHeight;
226 }
228 uint32_t Connector::subpixel() const
229 {
230 return m_priv->drm_connector->subpixel;
231 }
233 const string& Connector::subpixel_str() const
234 {
235 return subpix_str.at(subpixel());
236 }
238 std::vector<Videomode> Connector::get_modes() const
239 {
240 vector<Videomode> modes;
242 for (int i = 0; i < m_priv->drm_connector->count_modes; i++)
243 modes.push_back(drm_mode_to_video_mode(
244 m_priv->drm_connector->modes[i]));
246 return modes;
247 }
249 std::vector<Encoder*> Connector::get_encoders() const
250 {
251 vector<Encoder*> encoders;
253 for (int i = 0; i < m_priv->drm_connector->count_encoders; i++) {
254 auto enc = card().get_encoder(m_priv->drm_connector->encoders[i]);
255 encoders.push_back(enc);
256 }
257 return encoders;
258 }
260 }