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 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 80 Connector::~Connector() 81 { 82 drmModeFreeConnector(m_priv->drm_connector); 83 delete m_priv; 84 } 85 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 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 114 void Connector::restore_mode() 115 { 116 if (m_saved_crtc) 117 m_saved_crtc->restore_mode(this); 118 } 119 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]; 125 126 return drm_mode_to_video_mode(drmmode); 127 } 128 129 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 153 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 192 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 198 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 213 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 221 uint32_t Connector::connector_type() const 222 { 223 return m_priv->drm_connector->connector_type; 224 } 225 226 uint32_t Connector::connector_type_id() const 227 { 228 return m_priv->drm_connector->connector_type_id; 229 } 230 231 uint32_t Connector::mmWidth() const 232 { 233 return m_priv->drm_connector->mmWidth; 234 } 235 236 uint32_t Connector::mmHeight() const 237 { 238 return m_priv->drm_connector->mmHeight; 239 } 240 241 uint32_t Connector::subpixel() const 242 { 243 return m_priv->drm_connector->subpixel; 244 } 245 246 const string& Connector::subpixel_str() const 247 { 248 return subpix_str.at(subpixel()); 249 } 250 251 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 262 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