1/*
2* Copyright (c) 2017, The Linux Foundation. All rights reserved.
3*
4* Redistribution and use in source and binary forms, with or without
5* modification, are permitted provided that the following conditions are
6* met:
7*   * Redistributions of source code must retain the above copyright
8*     notice, this list of conditions and the following disclaimer.
9*   * Redistributions in binary form must reproduce the above
10*     copyright notice, this list of conditions and the following
11*     disclaimer in the documentation and/or other materials provided
12*     with the distribution.
13*   * Neither the name of The Linux Foundation nor the names of its
14*     contributors may be used to endorse or promote products derived
15*     from this software without specific prior written permission.
16*
17* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*/
29
30#include <errno.h>
31
32#include "drm_master.h"
33#include "drm_res_mgr.h"
34
35#define DEBUG 0
36#define __CLASS__ "DRMResMgr"
37
38using std::mutex;
39using std::lock_guard;
40
41namespace drm_utils {
42
43DRMResMgr *DRMResMgr::s_instance = nullptr;
44mutex DRMResMgr::s_lock;
45
46static bool GetConnector(int dev_fd, drmModeRes *res, drmModeConnector **connector) {
47  for (auto i = 0; i < res->count_connectors; i++) {
48    drmModeConnector *conn = drmModeGetConnector(dev_fd, res->connectors[i]);
49    if (conn && conn->connector_type == DRM_MODE_CONNECTOR_DSI && conn->count_modes &&
50        conn->connection == DRM_MODE_CONNECTED) {
51      *connector = conn;
52      DRM_LOGI("Found connector %d", conn->connector_id);
53      return true;
54    }
55  }
56
57  return false;
58}
59
60static bool GetEncoder(int dev_fd, drmModeConnector *conn, drmModeEncoder **encoder) {
61  for (auto i = 0; i < conn->count_encoders; i++) {
62    drmModeEncoder *enc = drmModeGetEncoder(dev_fd, conn->encoders[i]);
63    if (enc && enc->encoder_type == DRM_MODE_ENCODER_DSI) {
64      *encoder = enc;
65      DRM_LOGI("Found encoder %d", enc->encoder_id);
66      return true;
67    }
68  }
69  return false;
70}
71
72static bool GetCrtc(int dev_fd, drmModeRes *res, drmModeEncoder *enc, drmModeCrtc **crtc) {
73  for (auto i = 0; i < res->count_crtcs; i++) {
74    if (enc->possible_crtcs & (1 << i)) {
75      drmModeCrtc *c = drmModeGetCrtc(dev_fd, res->crtcs[i]);
76      if (c) {
77        *crtc = c;
78        DRM_LOGI("Found crtc %d", c->crtc_id);
79        return true;
80      }
81    }
82  }
83
84  return false;
85}
86
87#define __CLASS__ "DRMResMgr"
88
89int DRMResMgr::GetInstance(DRMResMgr **res_mgr) {
90  lock_guard<mutex> obj(s_lock);
91
92  if (!s_instance) {
93    s_instance = new DRMResMgr();
94    if (s_instance->Init() < 0) {
95      delete s_instance;
96      s_instance = nullptr;
97      return -ENODEV;
98    }
99  }
100
101  *res_mgr = s_instance;
102  return 0;
103}
104
105int DRMResMgr::Init() {
106  DRMMaster *master = nullptr;
107  int dev_fd = -1;
108
109  int ret = DRMMaster::GetInstance(&master);
110  if (ret < 0) {
111    return ret;
112  }
113
114  master->GetHandle(&dev_fd);
115  drmModeRes *res = drmModeGetResources(dev_fd);
116  if (res == nullptr) {
117    DRM_LOGE("drmModeGetResources failed");
118    return -ENODEV;
119  }
120
121  drmModeConnector *conn = nullptr;
122  if (!GetConnector(dev_fd, res, &conn)) {
123    DRM_LOGE("Failed to find a connector");
124    return -ENODEV;
125  }
126
127  drmModeEncoder *enc = nullptr;
128  if (!GetEncoder(dev_fd, conn, &enc)) {
129    DRM_LOGE("Failed to find an encoder");
130    drmModeFreeConnector(conn);
131    return -ENODEV;
132  }
133
134  drmModeCrtc *crtc = nullptr;
135  if (!GetCrtc(dev_fd, res, enc, &crtc)) {
136    DRM_LOGE("Failed to find a crtc");
137    drmModeFreeEncoder(enc);
138    drmModeFreeConnector(conn);
139    drmModeFreeResources(res);
140    return -ENODEV;
141  }
142
143  res_ = res;
144  conn_ = conn;
145  enc_ = enc;
146  crtc_ = crtc;
147
148  return 0;
149}
150
151}  // namespace drm_utils
152