48c581564621640b951e5995e6dd3539da534621
[android/external-libkmsxx.git] / kms++ / src / connector.cpp
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 }
76 Connector::~Connector()
77 {
78         drmModeFreeConnector(m_priv->drm_connector);
79         delete m_priv;
80 }
82 void Connector::refresh()
83 {
84         drmModeFreeConnector(m_priv->drm_connector);
86         m_priv->drm_connector = drmModeGetConnector(this->card().fd(), this->id());
87         assert(m_priv->drm_connector);
89         // XXX drmModeGetConnector() does forced probe, which seems to change (at least) EDID blob id.
90         // XXX So refresh the props again here.
91         refresh_props();
93         const auto& name = connector_names.at(m_priv->drm_connector->connector_type);
94         m_fullname = name + "-" + to_string(m_priv->drm_connector->connector_type_id);
95 }
97 void Connector::setup()
98 {
99         if (m_priv->drm_connector->encoder_id != 0)
100                 m_current_encoder = card().get_encoder(m_priv->drm_connector->encoder_id);
101         else
102                 m_current_encoder = 0;
104         if (m_current_encoder)
105                 m_saved_crtc = m_current_encoder->get_crtc();
106         else
107                 m_saved_crtc = 0;
110 void Connector::restore_mode()
112         if (m_saved_crtc)
113                 m_saved_crtc->restore_mode(this);
116 Videomode Connector::get_default_mode() const
118         if (m_priv->drm_connector->count_modes == 0)
119                 throw invalid_argument("no modes available\n");
120         drmModeModeInfo drmmode = m_priv->drm_connector->modes[0];
122         return drm_mode_to_video_mode(drmmode);
125 Videomode Connector::get_mode(const string& mode) const
127         auto c = m_priv->drm_connector;
129         for (int i = 0; i < c->count_modes; i++)
130                 if (mode == c->modes[i].name)
131                         return drm_mode_to_video_mode(c->modes[i]);
133         throw invalid_argument(mode + ": mode not found");
136 Videomode Connector::get_mode(unsigned xres, unsigned yres, float vrefresh, bool ilace) const
138         auto c = m_priv->drm_connector;
140         for (int i = 0; i < c->count_modes; i++) {
141                 Videomode m = drm_mode_to_video_mode(c->modes[i]);
143                 if (m.hdisplay != xres || m.vdisplay != yres)
144                         continue;
146                 if (ilace != m.interlace())
147                         continue;
149                 if (vrefresh && vrefresh != m.calculated_vrefresh())
150                         continue;
152                 return m;
153         }
155         // If not found, do another round using rounded vrefresh
157         for (int i = 0; i < c->count_modes; i++) {
158                 Videomode m = drm_mode_to_video_mode(c->modes[i]);
160                 if (m.hdisplay != xres || m.vdisplay != yres)
161                         continue;
163                 if (ilace != m.interlace())
164                         continue;
166                 if (vrefresh && vrefresh != roundf(m.calculated_vrefresh()))
167                         continue;
169                 return m;
170         }
172         throw invalid_argument("mode not found");
175 bool Connector::connected() const
177         return m_priv->drm_connector->connection == DRM_MODE_CONNECTED ||
178                         m_priv->drm_connector->connection == DRM_MODE_UNKNOWNCONNECTION;
181 vector<Crtc*> Connector::get_possible_crtcs() const
183         vector<Crtc*> crtcs;
185         for (int i = 0; i < m_priv->drm_connector->count_encoders; ++i) {
186                 auto enc = card().get_encoder(m_priv->drm_connector->encoders[i]);
188                 auto l = enc->get_possible_crtcs();
190                 crtcs.insert(crtcs.end(), l.begin(), l.end());
191         }
193         return crtcs;
196 Crtc* Connector::get_current_crtc() const
198         if (m_current_encoder)
199                 return m_current_encoder->get_crtc();
200         else
201                 return 0;
204 uint32_t Connector::connector_type() const
206         return m_priv->drm_connector->connector_type;
209 uint32_t Connector::connector_type_id() const
211         return m_priv->drm_connector->connector_type_id;
214 uint32_t Connector::mmWidth() const
216         return m_priv->drm_connector->mmWidth;
219 uint32_t Connector::mmHeight() const
221         return m_priv->drm_connector->mmHeight;
224 uint32_t Connector::subpixel() const
226         return m_priv->drm_connector->subpixel;
229 const string& Connector::subpixel_str() const
231         return subpix_str.at(subpixel());
234 std::vector<Videomode> Connector::get_modes() const
236         vector<Videomode> modes;
238         for (int i = 0; i < m_priv->drm_connector->count_modes; i++)
239                 modes.push_back(drm_mode_to_video_mode(
240                                         m_priv->drm_connector->modes[i]));
242         return modes;
245 std::vector<Encoder*> Connector::get_encoders() const
247         vector<Encoder*> encoders;
249         for (int i = 0; i < m_priv->drm_connector->count_encoders; i++) {
250                 auto enc = card().get_encoder(m_priv->drm_connector->encoders[i]);
251                 encoders.push_back(enc);
252         }
253         return encoders;