#include #include #include #include #include #include #include "helpers.h" using namespace std; namespace kms { static const map connector_names = { { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, { DRM_MODE_CONNECTOR_VGA, "VGA" }, { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, { DRM_MODE_CONNECTOR_Composite, "Composite" }, { DRM_MODE_CONNECTOR_SVIDEO, "S-Video" }, { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, { DRM_MODE_CONNECTOR_Component, "Component" }, { DRM_MODE_CONNECTOR_9PinDIN, "9-Pin-DIN" }, { DRM_MODE_CONNECTOR_DisplayPort, "DP" }, { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, { DRM_MODE_CONNECTOR_TV, "TV" }, { DRM_MODE_CONNECTOR_eDP, "eDP" }, { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" }, { DRM_MODE_CONNECTOR_DSI, "DSI" }, }; static const map connection_str = { { 0, "" }, { DRM_MODE_CONNECTED, "Connected" }, { DRM_MODE_DISCONNECTED, "Disconnected" }, { DRM_MODE_UNKNOWNCONNECTION, "Unknown" }, }; static const map subpix_str = { #define DEF_SUBPIX(c) { DRM_MODE_SUBPIXEL_##c, #c } DEF_SUBPIX(UNKNOWN), DEF_SUBPIX(HORIZONTAL_RGB), DEF_SUBPIX(HORIZONTAL_BGR), DEF_SUBPIX(VERTICAL_RGB), DEF_SUBPIX(VERTICAL_BGR), DEF_SUBPIX(NONE), #undef DEF_SUBPIX }; struct ConnectorPriv { drmModeConnectorPtr drm_connector; }; Connector::Connector(Card &card, uint32_t id, uint32_t idx) :DrmPropObject(card, id, DRM_MODE_OBJECT_CONNECTOR, idx) { m_priv = new ConnectorPriv(); m_priv->drm_connector = drmModeGetConnector(this->card().fd(), this->id()); assert(m_priv->drm_connector); // XXX drmModeGetConnector() does forced probe, which seems to change (at least) EDID blob id. // XXX So refresh the props again here. refresh_props(); const auto& name = connector_names.at(m_priv->drm_connector->connector_type); m_fullname = name + "-" + to_string(m_priv->drm_connector->connector_type_id); } Connector::~Connector() { drmModeFreeConnector(m_priv->drm_connector); delete m_priv; } void Connector::setup() { if (m_priv->drm_connector->encoder_id != 0) m_current_encoder = card().get_encoder(m_priv->drm_connector->encoder_id); else m_current_encoder = 0; if (m_current_encoder) m_saved_crtc = m_current_encoder->get_crtc(); else m_saved_crtc = 0; } void Connector::restore_mode() { if (m_saved_crtc) m_saved_crtc->restore_mode(this); } Videomode Connector::get_default_mode() const { if (m_priv->drm_connector->count_modes == 0) throw invalid_argument("no modes available\n"); drmModeModeInfo drmmode = m_priv->drm_connector->modes[0]; return drm_mode_to_video_mode(drmmode); } Videomode Connector::get_mode(const string& mode) const { auto c = m_priv->drm_connector; for (int i = 0; i < c->count_modes; i++) if (mode == c->modes[i].name) return drm_mode_to_video_mode(c->modes[i]); throw invalid_argument(mode + ": mode not found"); } Videomode Connector::get_mode(unsigned xres, unsigned yres, unsigned refresh, bool ilace) const { auto c = m_priv->drm_connector; for (int i = 0; i < c->count_modes; i++) { drmModeModeInfo& m = c->modes[i]; if (m.hdisplay != xres || m.vdisplay != yres) continue; if (refresh && m.vrefresh != refresh) continue; if (ilace != !!(m.flags & DRM_MODE_FLAG_INTERLACE)) continue; return drm_mode_to_video_mode(c->modes[i]); } throw invalid_argument("mode not found"); } bool Connector::connected() const { return m_priv->drm_connector->connection == DRM_MODE_CONNECTED || m_priv->drm_connector->connection == DRM_MODE_UNKNOWNCONNECTION; } vector Connector::get_possible_crtcs() const { vector crtcs; for (int i = 0; i < m_priv->drm_connector->count_encoders; ++i) { auto enc = card().get_encoder(m_priv->drm_connector->encoders[i]); auto l = enc->get_possible_crtcs(); crtcs.insert(crtcs.end(), l.begin(), l.end()); } return crtcs; } Crtc* Connector::get_current_crtc() const { if (m_current_encoder) return m_current_encoder->get_crtc(); else return 0; } uint32_t Connector::connector_type() const { return m_priv->drm_connector->connector_type; } uint32_t Connector::connector_type_id() const { return m_priv->drm_connector->connector_type_id; } uint32_t Connector::mmWidth() const { return m_priv->drm_connector->mmWidth; } uint32_t Connector::mmHeight() const { return m_priv->drm_connector->mmHeight; } uint32_t Connector::subpixel() const { return m_priv->drm_connector->subpixel; } const string& Connector::subpixel_str() const { return subpix_str.at(subpixel()); } std::vector Connector::get_modes() const { vector modes; for (int i = 0; i < m_priv->drm_connector->count_modes; i++) modes.push_back(drm_mode_to_video_mode( m_priv->drm_connector->modes[i])); return modes; } std::vector Connector::get_encoders() const { vector encoders; for (int i = 0; i < m_priv->drm_connector->count_encoders; i++) { auto enc = card().get_encoder(m_priv->drm_connector->encoders[i]); encoders.push_back(enc); } return encoders; } }