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 }
77 Connector::~Connector()
78 {
79 drmModeFreeConnector(m_priv->drm_connector);
80 delete m_priv;
81 }
83 void Connector::setup()
84 {
85 if (m_priv->drm_connector->encoder_id != 0)
86 m_current_encoder = card().get_encoder(m_priv->drm_connector->encoder_id);
87 else
88 m_current_encoder = 0;
90 if (m_current_encoder)
91 m_saved_crtc = m_current_encoder->get_crtc();
92 else
93 m_saved_crtc = 0;
94 }
96 void Connector::restore_mode()
97 {
98 if (m_saved_crtc)
99 m_saved_crtc->restore_mode(this);
100 }
102 Videomode Connector::get_default_mode() const
103 {
104 if (m_priv->drm_connector->count_modes == 0)
105 throw invalid_argument("no modes available\n");
106 drmModeModeInfo drmmode = m_priv->drm_connector->modes[0];
108 return drm_mode_to_video_mode(drmmode);
109 }
111 Videomode Connector::get_mode(const string& mode) const
112 {
113 auto c = m_priv->drm_connector;
115 for (int i = 0; i < c->count_modes; i++)
116 if (mode == c->modes[i].name)
117 return drm_mode_to_video_mode(c->modes[i]);
119 throw invalid_argument(mode + ": mode not found");
120 }
122 Videomode Connector::get_mode(unsigned xres, unsigned yres, float vrefresh, bool ilace) const
123 {
124 auto c = m_priv->drm_connector;
126 for (int i = 0; i < c->count_modes; i++) {
127 Videomode m = drm_mode_to_video_mode(c->modes[i]);
129 if (m.hdisplay != xres || m.vdisplay != yres)
130 continue;
132 if (ilace != m.interlace())
133 continue;
135 if (vrefresh && std::abs(m.calculated_vrefresh() - vrefresh) >= 0.001)
136 continue;
138 return m;
139 }
141 throw invalid_argument("mode not found");
142 }
144 bool Connector::connected() const
145 {
146 return m_priv->drm_connector->connection == DRM_MODE_CONNECTED ||
147 m_priv->drm_connector->connection == DRM_MODE_UNKNOWNCONNECTION;
148 }
150 vector<Crtc*> Connector::get_possible_crtcs() const
151 {
152 vector<Crtc*> crtcs;
154 for (int i = 0; i < m_priv->drm_connector->count_encoders; ++i) {
155 auto enc = card().get_encoder(m_priv->drm_connector->encoders[i]);
157 auto l = enc->get_possible_crtcs();
159 crtcs.insert(crtcs.end(), l.begin(), l.end());
160 }
162 return crtcs;
163 }
165 Crtc* Connector::get_current_crtc() const
166 {
167 if (m_current_encoder)
168 return m_current_encoder->get_crtc();
169 else
170 return 0;
171 }
173 uint32_t Connector::connector_type() const
174 {
175 return m_priv->drm_connector->connector_type;
176 }
178 uint32_t Connector::connector_type_id() const
179 {
180 return m_priv->drm_connector->connector_type_id;
181 }
183 uint32_t Connector::mmWidth() const
184 {
185 return m_priv->drm_connector->mmWidth;
186 }
188 uint32_t Connector::mmHeight() const
189 {
190 return m_priv->drm_connector->mmHeight;
191 }
193 uint32_t Connector::subpixel() const
194 {
195 return m_priv->drm_connector->subpixel;
196 }
198 const string& Connector::subpixel_str() const
199 {
200 return subpix_str.at(subpixel());
201 }
203 std::vector<Videomode> Connector::get_modes() const
204 {
205 vector<Videomode> modes;
207 for (int i = 0; i < m_priv->drm_connector->count_modes; i++)
208 modes.push_back(drm_mode_to_video_mode(
209 m_priv->drm_connector->modes[i]));
211 return modes;
212 }
214 std::vector<Encoder*> Connector::get_encoders() const
215 {
216 vector<Encoder*> encoders;
218 for (int i = 0; i < m_priv->drm_connector->count_encoders; i++) {
219 auto enc = card().get_encoder(m_priv->drm_connector->encoders[i]);
220 encoders.push_back(enc);
221 }
222 return encoders;
223 }
225 }