Home | History | Annotate | Download | only in src
      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