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 #pragma once
18
19 #include <xf86drmMode.h>
20
21 #include <cinttypes>
22 #include <cstdint>
23 #include <map>
24 #include <optional>
25 #include <string>
26 #include <vector>
27
28 #include "drm/DrmUnique.h"
29 #include "utils/fd.h"
30 #include "utils/log.h"
31
32 namespace android {
33
34 class DrmProperty {
35 public:
36 DrmProperty() = default;
37 DrmProperty(const SharedFd &fd, uint32_t obj_id, drmModePropertyPtr p,
38 uint64_t value);
39 DrmProperty(const DrmProperty &) = delete;
40 DrmProperty &operator=(const DrmProperty &) = delete;
41
42 auto Init(const SharedFd &fd, uint32_t obj_id, drmModePropertyPtr p,
43 uint64_t value) -> void;
44 std::tuple<uint64_t, int> GetEnumValueWithName(const std::string &name) const;
45
GetId()46 auto GetId() const {
47 return id_;
48 }
49
GetName()50 auto GetName() const {
51 return name_;
52 }
53
54 auto GetValue() const -> std::optional<uint64_t>;
55
IsImmutable()56 bool IsImmutable() const {
57 return id_ != 0 && (flags_ & DRM_MODE_PROP_IMMUTABLE) != 0;
58 }
59
IsRange()60 bool IsRange() const {
61 return id_ != 0 && (flags_ & DRM_MODE_PROP_RANGE) != 0;
62 }
63
IsBitmask()64 bool IsBitmask() const {
65 return id_ != 0 && (flags_ & DRM_MODE_PROP_BITMASK) != 0;
66 }
67
68 auto RangeMin() const -> std::tuple<int, uint64_t>;
69 auto RangeMax() const -> std::tuple<int, uint64_t>;
70
71 [[nodiscard]] auto AtomicSet(drmModeAtomicReq &pset, uint64_t value) const
72 -> bool;
73
74 template <class E>
75 auto AddEnumToMap(const std::string &name, E key, std::map<E, uint64_t> &map)
76 -> bool;
77
78 template <class E>
79 auto AddEnumToMapReverse(const std::string &name, E value,
80 std::map<uint64_t, E> &map) -> bool;
81
82 auto GetEnumMask(uint64_t &mask) -> bool;
83
84 explicit operator bool() const {
85 return id_ != 0;
86 }
87
88 auto GetEnumNameFromValue(uint64_t value) const -> std::optional<std::string>;
89
IsBlob()90 bool IsBlob() const {
91 return id_ != 0 && (flags_ & DRM_MODE_PROP_BLOB) != 0;
92 }
93 template <typename T>
94 bool GetBlobData(std::vector<T> &data_out) const;
95
96 private:
97 class DrmPropertyEnum {
98 public:
99 explicit DrmPropertyEnum(drm_mode_property_enum *e);
100 ~DrmPropertyEnum() = default;
101
102 uint64_t value;
103 std::string name;
104 };
105
106 SharedFd fd_ = nullptr;
107 uint32_t obj_id_ = 0;
108 uint32_t id_ = 0;
109
110 uint32_t flags_ = 0;
111 std::string name_;
112 uint64_t value_ = 0;
113
114 std::vector<uint64_t> values_;
115 std::vector<DrmPropertyEnum> enums_;
116 std::vector<uint32_t> blob_ids_;
117 };
118
119 template <class E>
120 auto DrmProperty::AddEnumToMap(const std::string &name, E key,
121 std::map<E, uint64_t> &map) -> bool {
122 uint64_t enum_value = UINT64_MAX;
123 int err = 0;
124 std::tie(enum_value, err) = GetEnumValueWithName(name);
125 if (err == 0) {
126 map[key] = enum_value;
127 return true;
128 }
129
130 return false;
131 }
132
133 template <class E>
134 auto DrmProperty::AddEnumToMapReverse(const std::string &name, E value,
135 std::map<uint64_t, E> &map) -> bool {
136 uint64_t enum_value = UINT64_MAX;
137 int err = 0;
138 std::tie(enum_value, err) = GetEnumValueWithName(name);
139 if (err == 0) {
140 map[enum_value] = value;
141 return true;
142 }
143
144 return false;
145 }
146
147 template <typename T>
GetBlobData(std::vector<T> & data_out)148 bool DrmProperty::GetBlobData(std::vector<T> &data_out) const {
149 auto value = GetValue();
150 if (!fd_) {
151 ALOGE("Could not read blob data from property %s: No fd", name_.c_str());
152 return false;
153 }
154 if (!IsBlob()) {
155 ALOGE("Property %s is not blob type", name_.c_str());
156 return false;
157 }
158 if (!value.has_value()) {
159 ALOGE("Could not read blob data from property %s: No blob id",
160 name_.c_str());
161 return false;
162 }
163
164 auto blob = MakeDrmModePropertyBlobUnique(*fd_, value.value());
165 if (blob == nullptr) {
166 ALOGE("Failed to read blob with id=%" PRIu64 " from property %s",
167 value.value(), name_.c_str());
168 return false;
169 }
170
171 if (blob->length % sizeof(T) != 0) {
172 ALOGE(
173 "Property %s blob size of %u bytes is not divisible by type argument "
174 "size of %zu bytes",
175 name_.c_str(), blob->length, sizeof(T));
176 return false;
177 }
178
179 auto cast_data = static_cast<T *>(blob->data);
180 size_t cast_data_length = blob->length / sizeof(T);
181 data_out.assign(cast_data, cast_data + cast_data_length);
182
183 return true;
184 }
185
186 } // namespace android
187