• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "hwc-drm-device"
18 
19 #include "DrmDevice.h"
20 
21 #include <xf86drm.h>
22 #include <xf86drmMode.h>
23 
24 #include <cinttypes>
25 #include <cstdint>
26 #include <string>
27 
28 #include "drm/DrmAtomicStateManager.h"
29 #include "drm/DrmPlane.h"
30 #include "drm/ResourceManager.h"
31 #include "utils/log.h"
32 #include "utils/properties.h"
33 
34 namespace android {
35 
CreateInstance(std::string const & path,ResourceManager * res_man)36 auto DrmDevice::CreateInstance(std::string const &path,
37                                ResourceManager *res_man)
38     -> std::unique_ptr<DrmDevice> {
39   if (!IsKMSDev(path.c_str())) {
40     return {};
41   }
42 
43   auto device = std::unique_ptr<DrmDevice>(new DrmDevice(res_man));
44 
45   if (device->Init(path.c_str()) != 0) {
46     return {};
47   }
48 
49   return device;
50 }
51 
DrmDevice(ResourceManager * res_man)52 DrmDevice::DrmDevice(ResourceManager *res_man) : res_man_(res_man) {
53   drm_fb_importer_ = std::make_unique<DrmFbImporter>(*this);
54 }
55 
Init(const char * path)56 auto DrmDevice::Init(const char *path) -> int {
57   /* TODO: Use drmOpenControl here instead */
58   fd_ = UniqueFd(open(path, O_RDWR | O_CLOEXEC));
59   if (!fd_) {
60     // NOLINTNEXTLINE(concurrency-mt-unsafe): Fixme
61     ALOGE("Failed to open dri %s: %s", path, strerror(errno));
62     return -ENODEV;
63   }
64 
65   int ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
66   if (ret != 0) {
67     ALOGE("Failed to set universal plane cap %d", ret);
68     return ret;
69   }
70 
71   ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_ATOMIC, 1);
72   if (ret != 0) {
73     ALOGE("Failed to set atomic cap %d", ret);
74     return ret;
75   }
76 
77 #ifdef DRM_CLIENT_CAP_WRITEBACK_CONNECTORS
78   ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
79   if (ret != 0) {
80     ALOGI("Failed to set writeback cap %d", ret);
81   }
82 #endif
83 
84   uint64_t cap_value = 0;
85   if (drmGetCap(GetFd(), DRM_CAP_ADDFB2_MODIFIERS, &cap_value) != 0) {
86     ALOGW("drmGetCap failed. Fallback to no modifier support.");
87     cap_value = 0;
88   }
89   HasAddFb2ModifiersSupport_ = cap_value != 0;
90 
91   drmSetMaster(GetFd());
92   if (drmIsMaster(GetFd()) == 0) {
93     ALOGE("DRM/KMS master access required");
94     return -EACCES;
95   }
96 
97   auto res = MakeDrmModeResUnique(GetFd());
98   if (!res) {
99     ALOGE("Failed to get DrmDevice resources");
100     return -ENODEV;
101   }
102 
103   min_resolution_ = std::pair<uint32_t, uint32_t>(res->min_width,
104                                                   res->min_height);
105   max_resolution_ = std::pair<uint32_t, uint32_t>(res->max_width,
106                                                   res->max_height);
107 
108   for (int i = 0; i < res->count_crtcs; ++i) {
109     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
110     auto crtc = DrmCrtc::CreateInstance(*this, res->crtcs[i], i);
111     if (crtc) {
112       crtcs_.emplace_back(std::move(crtc));
113     }
114   }
115 
116   for (int i = 0; i < res->count_encoders; ++i) {
117     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
118     auto enc = DrmEncoder::CreateInstance(*this, res->encoders[i], i);
119     if (enc) {
120       encoders_.emplace_back(std::move(enc));
121     }
122   }
123 
124   for (int i = 0; i < res->count_connectors; ++i) {
125     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
126     auto conn = DrmConnector::CreateInstance(*this, res->connectors[i], i);
127 
128     if (!conn) {
129       continue;
130     }
131 
132     if (conn->IsWriteback()) {
133       writeback_connectors_.emplace_back(std::move(conn));
134     } else {
135       connectors_.emplace_back(std::move(conn));
136     }
137   }
138 
139   auto plane_res = MakeDrmModePlaneResUnique(GetFd());
140   if (!plane_res) {
141     ALOGE("Failed to get plane resources");
142     return -ENOENT;
143   }
144 
145   for (uint32_t i = 0; i < plane_res->count_planes; ++i) {
146     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
147     auto plane = DrmPlane::CreateInstance(*this, plane_res->planes[i]);
148 
149     if (plane) {
150       planes_.emplace_back(std::move(plane));
151     }
152   }
153 
154   return 0;
155 }
156 
RegisterUserPropertyBlob(void * data,size_t length) const157 auto DrmDevice::RegisterUserPropertyBlob(void *data, size_t length) const
158     -> DrmModeUserPropertyBlobUnique {
159   struct drm_mode_create_blob create_blob {};
160   create_blob.length = length;
161   // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
162   create_blob.data = (__u64)data;
163 
164   int ret = drmIoctl(GetFd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob);
165   if (ret != 0) {
166     ALOGE("Failed to create mode property blob %d", ret);
167     return {};
168   }
169 
170   return DrmModeUserPropertyBlobUnique(
171       new uint32_t(create_blob.blob_id), [this](const uint32_t *it) {
172         struct drm_mode_destroy_blob destroy_blob {};
173         destroy_blob.blob_id = (__u32)*it;
174         int err = drmIoctl(GetFd(), DRM_IOCTL_MODE_DESTROYPROPBLOB,
175                            &destroy_blob);
176         if (err != 0) {
177           ALOGE("Failed to destroy mode property blob %" PRIu32 "/%d", *it,
178                 err);
179         }
180         // NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
181         delete it;
182       });
183 }
184 
GetProperty(uint32_t obj_id,uint32_t obj_type,const char * prop_name,DrmProperty * property) const185 int DrmDevice::GetProperty(uint32_t obj_id, uint32_t obj_type,
186                            const char *prop_name, DrmProperty *property) const {
187   drmModeObjectPropertiesPtr props = nullptr;
188 
189   props = drmModeObjectGetProperties(GetFd(), obj_id, obj_type);
190   if (props == nullptr) {
191     ALOGE("Failed to get properties for %d/%x", obj_id, obj_type);
192     return -ENODEV;
193   }
194 
195   bool found = false;
196   for (int i = 0; !found && (size_t)i < props->count_props; ++i) {
197     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
198     drmModePropertyPtr p = drmModeGetProperty(GetFd(), props->props[i]);
199     if (strcmp(p->name, prop_name) == 0) {
200       // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
201       property->Init(obj_id, p, props->prop_values[i]);
202       found = true;
203     }
204     drmModeFreeProperty(p);
205   }
206 
207   drmModeFreeObjectProperties(props);
208   return found ? 0 : -ENOENT;
209 }
210 
GetName() const211 std::string DrmDevice::GetName() const {
212   auto *ver = drmGetVersion(GetFd());
213   if (ver == nullptr) {
214     ALOGW("Failed to get drm version for fd=%d", GetFd());
215     return "generic";
216   }
217 
218   std::string name(ver->name);
219   drmFreeVersion(ver);
220   return name;
221 }
222 
IsKMSDev(const char * path)223 auto DrmDevice::IsKMSDev(const char *path) -> bool {
224   auto fd = UniqueFd(open(path, O_RDWR | O_CLOEXEC));
225   if (!fd) {
226     return false;
227   }
228 
229   auto res = MakeDrmModeResUnique(fd.Get());
230   if (!res) {
231     return false;
232   }
233 
234   bool is_kms = res->count_crtcs > 0 && res->count_connectors > 0 &&
235                 res->count_encoders > 0;
236 
237   return is_kms;
238 }
239 
GetConnectors()240 auto DrmDevice::GetConnectors()
241     -> const std::vector<std::unique_ptr<DrmConnector>> & {
242   return connectors_;
243 }
244 
GetPlanes()245 auto DrmDevice::GetPlanes() -> const std::vector<std::unique_ptr<DrmPlane>> & {
246   return planes_;
247 }
248 
GetCrtcs()249 auto DrmDevice::GetCrtcs() -> const std::vector<std::unique_ptr<DrmCrtc>> & {
250   return crtcs_;
251 }
252 
GetEncoders()253 auto DrmDevice::GetEncoders()
254     -> const std::vector<std::unique_ptr<DrmEncoder>> & {
255   return encoders_;
256 }
257 
258 }  // namespace android
259