1 #include <stdio.h>
2 #include <iostream>
3 #include <unistd.h>
4 #include <fcntl.h>
5 #include <cassert>
7 #include "kms++.h"
8 #include "helpers.h"
10 using namespace std;
12 namespace kms
13 {
16 static const map<int, string> connector_names = {
17 { DRM_MODE_CONNECTOR_Unknown, "Unknown" },
18 { DRM_MODE_CONNECTOR_VGA, "VGA" },
19 { DRM_MODE_CONNECTOR_DVII, "DVI-I" },
20 { DRM_MODE_CONNECTOR_DVID, "DVI-D" },
21 { DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
22 { DRM_MODE_CONNECTOR_Composite, "Composite" },
23 { DRM_MODE_CONNECTOR_SVIDEO, "S-Video" },
24 { DRM_MODE_CONNECTOR_LVDS, "LVDS" },
25 { DRM_MODE_CONNECTOR_Component, "Component" },
26 { DRM_MODE_CONNECTOR_9PinDIN, "9-Pin-DIN" },
27 { DRM_MODE_CONNECTOR_DisplayPort, "DP" },
28 { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
29 { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
30 { DRM_MODE_CONNECTOR_TV, "TV" },
31 { DRM_MODE_CONNECTOR_eDP, "eDP" },
32 { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" },
33 { DRM_MODE_CONNECTOR_DSI, "DSI" },
34 };
36 static const map<int, string> connection_str = {
37 { 0, "<unknown>" },
38 { DRM_MODE_CONNECTED, "Connected" },
39 { DRM_MODE_DISCONNECTED, "Disconnected" },
40 { DRM_MODE_UNKNOWNCONNECTION, "Unknown" },
41 };
43 static const map<int, string> subpix_str = {
44 #define DEF_SUBPIX(c) { DRM_MODE_SUBPIXEL_##c, #c }
45 DEF_SUBPIX(UNKNOWN),
46 DEF_SUBPIX(HORIZONTAL_RGB),
47 DEF_SUBPIX(HORIZONTAL_BGR),
48 DEF_SUBPIX(VERTICAL_RGB),
49 DEF_SUBPIX(VERTICAL_BGR),
50 DEF_SUBPIX(NONE),
51 #undef DEF_SUBPIX
52 };
54 struct ConnectorPriv
55 {
56 drmModeConnectorPtr drm_connector;
57 };
59 Connector::Connector(Card &card, uint32_t id, uint32_t idx)
60 :DrmPropObject(card, id, DRM_MODE_OBJECT_CONNECTOR, idx)
61 {
62 m_priv = new ConnectorPriv();
64 m_priv->drm_connector = drmModeGetConnector(this->card().fd(), this->id());
65 assert(m_priv->drm_connector);
67 // XXX drmModeGetConnector() does forced probe, which seems to change (at least) EDID blob id.
68 // XXX So refresh the props again here.
69 refresh_props();
71 const auto& name = connector_names.at(m_priv->drm_connector->connector_type);
72 m_fullname = name + "-" + to_string(m_priv->drm_connector->connector_type_id);
73 }
76 Connector::~Connector()
77 {
78 drmModeFreeConnector(m_priv->drm_connector);
79 delete m_priv;
80 }
82 void Connector::setup()
83 {
84 if (m_priv->drm_connector->encoder_id != 0)
85 m_current_encoder = card().get_encoder(m_priv->drm_connector->encoder_id);
86 else
87 m_current_encoder = 0;
89 if (m_current_encoder)
90 m_saved_crtc = m_current_encoder->get_crtc();
91 else
92 m_saved_crtc = 0;
93 }
95 void Connector::restore_mode()
96 {
97 if (m_saved_crtc)
98 m_saved_crtc->restore_mode(this);
99 }
101 Videomode Connector::get_default_mode() const
102 {
103 if (m_priv->drm_connector->count_modes == 0)
104 throw invalid_argument("no modes available\n");
105 drmModeModeInfo drmmode = m_priv->drm_connector->modes[0];
107 return drm_mode_to_video_mode(drmmode);
108 }
110 Videomode Connector::get_mode(const string& mode) const
111 {
112 auto c = m_priv->drm_connector;
114 for (int i = 0; i < c->count_modes; i++)
115 if (mode == c->modes[i].name)
116 return drm_mode_to_video_mode(c->modes[i]);
118 throw invalid_argument(mode + ": mode not found");
119 }
121 Videomode Connector::get_mode(unsigned xres, unsigned yres, unsigned refresh, bool ilace) const
122 {
123 auto c = m_priv->drm_connector;
125 for (int i = 0; i < c->count_modes; i++) {
126 drmModeModeInfo& m = c->modes[i];
128 if (m.hdisplay != xres || m.vdisplay != yres)
129 continue;
131 if (refresh && m.vrefresh != refresh)
132 continue;
134 if (ilace != !!(m.flags & DRM_MODE_FLAG_INTERLACE))
135 continue;
137 return drm_mode_to_video_mode(c->modes[i]);
138 }
140 throw invalid_argument("mode not found");
141 }
143 bool Connector::connected() const
144 {
145 return m_priv->drm_connector->connection == DRM_MODE_CONNECTED ||
146 m_priv->drm_connector->connection == DRM_MODE_UNKNOWNCONNECTION;
147 }
149 vector<Crtc*> Connector::get_possible_crtcs() const
150 {
151 vector<Crtc*> crtcs;
153 for (int i = 0; i < m_priv->drm_connector->count_encoders; ++i) {
154 auto enc = card().get_encoder(m_priv->drm_connector->encoders[i]);
156 auto l = enc->get_possible_crtcs();
158 crtcs.insert(crtcs.end(), l.begin(), l.end());
159 }
161 return crtcs;
162 }
164 Crtc* Connector::get_current_crtc() const
165 {
166 if (m_current_encoder)
167 return m_current_encoder->get_crtc();
168 else
169 return 0;
170 }
172 uint32_t Connector::connector_type() const
173 {
174 return m_priv->drm_connector->connector_type;
175 }
177 uint32_t Connector::connector_type_id() const
178 {
179 return m_priv->drm_connector->connector_type_id;
180 }
182 uint32_t Connector::mmWidth() const
183 {
184 return m_priv->drm_connector->mmWidth;
185 }
187 uint32_t Connector::mmHeight() const
188 {
189 return m_priv->drm_connector->mmHeight;
190 }
192 uint32_t Connector::subpixel() const
193 {
194 return m_priv->drm_connector->subpixel;
195 }
197 const string& Connector::subpixel_str() const
198 {
199 return subpix_str.at(subpixel());
200 }
202 std::vector<Videomode> Connector::get_modes() const
203 {
204 vector<Videomode> modes;
206 for (int i = 0; i < m_priv->drm_connector->count_modes; i++)
207 modes.push_back(drm_mode_to_video_mode(
208 m_priv->drm_connector->modes[i]));
210 return modes;
211 }
213 std::vector<Encoder*> Connector::get_encoders() const
214 {
215 vector<Encoder*> encoders;
217 for (int i = 0; i < m_priv->drm_connector->count_encoders; i++) {
218 auto enc = card().get_encoder(m_priv->drm_connector->encoders[i]);
219 encoders.push_back(enc);
220 }
221 return encoders;
222 }
224 }