• 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 <fcntl.h>
22 #include <xf86drm.h>
23 #include <xf86drmMode.h>
24 
25 #include <cinttypes>
26 #include <cstdint>
27 #include <string>
28 
29 #include "drm/DrmAtomicStateManager.h"
30 #include "drm/DrmPlane.h"
31 #include "utils/log.h"
32 #include "utils/properties.h"
33 
34 namespace android {
35 
DrmDevice()36 DrmDevice::DrmDevice() {
37   drm_fb_importer_ = std::make_unique<DrmFbImporter>(*this);
38 }
39 
Init(const char * path)40 auto DrmDevice::Init(const char *path) -> int {
41   /* TODO: Use drmOpenControl here instead */
42   fd_ = UniqueFd(open(path, O_RDWR | O_CLOEXEC));
43   if (!fd_) {
44     // NOLINTNEXTLINE(concurrency-mt-unsafe): Fixme
45     ALOGE("Failed to open dri %s: %s", path, strerror(errno));
46     return -ENODEV;
47   }
48 
49   int ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
50   if (ret != 0) {
51     ALOGE("Failed to set universal plane cap %d", ret);
52     return ret;
53   }
54 
55   ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_ATOMIC, 1);
56   if (ret != 0) {
57     ALOGE("Failed to set atomic cap %d", ret);
58     return ret;
59   }
60 
61 #ifdef DRM_CLIENT_CAP_WRITEBACK_CONNECTORS
62   ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
63   if (ret != 0) {
64     ALOGI("Failed to set writeback cap %d", ret);
65   }
66 #endif
67 
68   uint64_t cap_value = 0;
69   if (drmGetCap(GetFd(), DRM_CAP_ADDFB2_MODIFIERS, &cap_value) != 0) {
70     ALOGW("drmGetCap failed. Fallback to no modifier support.");
71     cap_value = 0;
72   }
73   HasAddFb2ModifiersSupport_ = cap_value != 0;
74 
75   drmSetMaster(GetFd());
76   if (drmIsMaster(GetFd()) == 0) {
77     ALOGE("DRM/KMS master access required");
78     return -EACCES;
79   }
80 
81   auto res = MakeDrmModeResUnique(GetFd());
82   if (!res) {
83     ALOGE("Failed to get DrmDevice resources");
84     return -ENODEV;
85   }
86 
87   min_resolution_ = std::pair<uint32_t, uint32_t>(res->min_width,
88                                                   res->min_height);
89   max_resolution_ = std::pair<uint32_t, uint32_t>(res->max_width,
90                                                   res->max_height);
91 
92   for (int i = 0; i < res->count_crtcs; ++i) {
93     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
94     auto crtc = DrmCrtc::CreateInstance(*this, res->crtcs[i], i);
95     if (crtc) {
96       crtcs_.emplace_back(std::move(crtc));
97     }
98   }
99 
100   for (int i = 0; i < res->count_encoders; ++i) {
101     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
102     auto enc = DrmEncoder::CreateInstance(*this, res->encoders[i], i);
103     if (enc) {
104       encoders_.emplace_back(std::move(enc));
105     }
106   }
107 
108   for (int i = 0; i < res->count_connectors; ++i) {
109     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
110     auto conn = DrmConnector::CreateInstance(*this, res->connectors[i], i);
111 
112     if (!conn) {
113       continue;
114     }
115 
116     if (conn->IsWriteback()) {
117       writeback_connectors_.emplace_back(std::move(conn));
118     } else {
119       connectors_.emplace_back(std::move(conn));
120     }
121   }
122 
123   auto plane_res = MakeDrmModePlaneResUnique(GetFd());
124   if (!plane_res) {
125     ALOGE("Failed to get plane resources");
126     return -ENOENT;
127   }
128 
129   for (uint32_t i = 0; i < plane_res->count_planes; ++i) {
130     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
131     auto plane = DrmPlane::CreateInstance(*this, plane_res->planes[i]);
132 
133     if (plane) {
134       planes_.emplace_back(std::move(plane));
135     }
136   }
137 
138   return 0;
139 }
140 
RegisterUserPropertyBlob(void * data,size_t length) const141 auto DrmDevice::RegisterUserPropertyBlob(void *data, size_t length) const
142     -> DrmModeUserPropertyBlobUnique {
143   struct drm_mode_create_blob create_blob {};
144   create_blob.length = length;
145   // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
146   create_blob.data = (__u64)data;
147 
148   int ret = drmIoctl(GetFd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob);
149   if (ret != 0) {
150     ALOGE("Failed to create mode property blob %d", ret);
151     return {};
152   }
153 
154   return DrmModeUserPropertyBlobUnique(
155       new uint32_t(create_blob.blob_id), [this](const uint32_t *it) {
156         struct drm_mode_destroy_blob destroy_blob {};
157         destroy_blob.blob_id = (__u32)*it;
158         int err = drmIoctl(GetFd(), DRM_IOCTL_MODE_DESTROYPROPBLOB,
159                            &destroy_blob);
160         if (err != 0) {
161           ALOGE("Failed to destroy mode property blob %" PRIu32 "/%d", *it,
162                 err);
163         }
164         // NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
165         delete it;
166       });
167 }
168 
GetProperty(uint32_t obj_id,uint32_t obj_type,const char * prop_name,DrmProperty * property) const169 int DrmDevice::GetProperty(uint32_t obj_id, uint32_t obj_type,
170                            const char *prop_name, DrmProperty *property) const {
171   drmModeObjectPropertiesPtr props = nullptr;
172 
173   props = drmModeObjectGetProperties(GetFd(), obj_id, obj_type);
174   if (props == nullptr) {
175     ALOGE("Failed to get properties for %d/%x", obj_id, obj_type);
176     return -ENODEV;
177   }
178 
179   bool found = false;
180   for (int i = 0; !found && (size_t)i < props->count_props; ++i) {
181     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
182     drmModePropertyPtr p = drmModeGetProperty(GetFd(), props->props[i]);
183     if (strcmp(p->name, prop_name) == 0) {
184       // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
185       property->Init(obj_id, p, props->prop_values[i]);
186       found = true;
187     }
188     drmModeFreeProperty(p);
189   }
190 
191   drmModeFreeObjectProperties(props);
192   return found ? 0 : -ENOENT;
193 }
194 
GetName() const195 std::string DrmDevice::GetName() const {
196   auto *ver = drmGetVersion(GetFd());
197   if (ver == nullptr) {
198     ALOGW("Failed to get drm version for fd=%d", GetFd());
199     return "generic";
200   }
201 
202   std::string name(ver->name);
203   drmFreeVersion(ver);
204   return name;
205 }
206 
IsKMSDev(const char * path)207 auto DrmDevice::IsKMSDev(const char *path) -> bool {
208   auto fd = UniqueFd(open(path, O_RDWR | O_CLOEXEC));
209   if (!fd) {
210     return false;
211   }
212 
213   auto res = MakeDrmModeResUnique(fd.Get());
214   if (!res) {
215     return false;
216   }
217 
218   bool is_kms = res->count_crtcs > 0 && res->count_connectors > 0 &&
219                 res->count_encoders > 0;
220 
221   return is_kms;
222 }
223 
GetConnectors()224 auto DrmDevice::GetConnectors()
225     -> const std::vector<std::unique_ptr<DrmConnector>> & {
226   return connectors_;
227 }
228 
GetPlanes()229 auto DrmDevice::GetPlanes() -> const std::vector<std::unique_ptr<DrmPlane>> & {
230   return planes_;
231 }
232 
GetCrtcs()233 auto DrmDevice::GetCrtcs() -> const std::vector<std::unique_ptr<DrmCrtc>> & {
234   return crtcs_;
235 }
236 
GetEncoders()237 auto DrmDevice::GetEncoders()
238     -> const std::vector<std::unique_ptr<DrmEncoder>> & {
239   return encoders_;
240 }
241 
242 }  // namespace android
243