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 #include "drmproperty.h"
18 #include "drmdevice.h"
19
20 #include <errno.h>
21 #include <stdint.h>
22 #include <string>
23
24 #include <xf86drmMode.h>
25 #include <log/log.h>
26 #include <inttypes.h>
27 #include <utils/Errors.h>
28
U642I64(uint64_t val)29 static inline int64_t U642I64(uint64_t val) {
30 return *(reinterpret_cast<int64_t *>(&val));
31 }
32
33 namespace android {
34
DrmPropertyEnum(drm_mode_property_enum * e)35 DrmProperty::DrmPropertyEnum::DrmPropertyEnum(drm_mode_property_enum *e)
36 : value_(e->value), name_(e->name) {
37 }
38
~DrmPropertyEnum()39 DrmProperty::DrmPropertyEnum::~DrmPropertyEnum() {
40 }
41
DrmProperty(drmModePropertyPtr p,uint64_t value)42 DrmProperty::DrmProperty(drmModePropertyPtr p, uint64_t value)
43 : id_(0), type_(DRM_PROPERTY_TYPE_INVALID), flags_(0), name_("") {
44 init(p, value);
45 }
46
init(drmModePropertyPtr p,uint64_t value)47 void DrmProperty::init(drmModePropertyPtr p, uint64_t value) {
48 id_ = p->prop_id;
49 flags_ = p->flags;
50 name_ = p->name;
51 value_ = value;
52
53 for (int i = 0; i < p->count_values; ++i) values_.push_back(p->values[i]);
54
55 for (int i = 0; i < p->count_enums; ++i) enums_.push_back(DrmPropertyEnum(&p->enums[i]));
56
57 for (int i = 0; i < p->count_blobs; ++i) blob_ids_.push_back(p->blob_ids[i]);
58
59 if ((flags_ & DRM_MODE_PROP_RANGE) || (flags_ & DRM_MODE_PROP_SIGNED_RANGE))
60 type_ = DRM_PROPERTY_TYPE_INT;
61 else if (flags_ & DRM_MODE_PROP_ENUM)
62 type_ = DRM_PROPERTY_TYPE_ENUM;
63 else if (flags_ & DRM_MODE_PROP_OBJECT)
64 type_ = DRM_PROPERTY_TYPE_OBJECT;
65 else if (flags_ & DRM_MODE_PROP_BLOB)
66 type_ = DRM_PROPERTY_TYPE_BLOB;
67 else if (flags_ & DRM_MODE_PROP_BITMASK)
68 type_ = DRM_PROPERTY_TYPE_BITMASK;
69 }
70
id() const71 uint32_t DrmProperty::id() const {
72 return id_;
73 }
74
name() const75 std::string DrmProperty::name() const {
76 return name_;
77 }
78
value() const79 std::tuple<int, uint64_t> DrmProperty::value() const {
80 if (type_ == DRM_PROPERTY_TYPE_BLOB)
81 return std::make_tuple(0, value_);
82
83 if (values_.size() == 0)
84 return std::make_tuple(-ENOENT, 0);
85
86 switch (type_) {
87 case DRM_PROPERTY_TYPE_INT:
88 return std::make_tuple(0, value_);
89
90 case DRM_PROPERTY_TYPE_BITMASK:
91 return std::make_tuple(0, value_);
92
93 case DRM_PROPERTY_TYPE_ENUM:
94 if (value_ >= enums_.size())
95 return std::make_tuple(-ENOENT, 0);
96
97 return std::make_tuple(0, enums_[value_].value_);
98
99 case DRM_PROPERTY_TYPE_OBJECT:
100 return std::make_tuple(0, value_);
101
102 default:
103 return std::make_tuple(-EINVAL, 0);
104 }
105 }
106
printProperty() const107 void DrmProperty::printProperty() const
108 {
109 ALOGD("=====================================================");
110 ALOGD("name: %s, type(%d), value_(%" PRId64 ")", name_.c_str(), type_, value_);
111 ALOGD("values.size(%zu)", values_.size());
112 for (uint32_t i = 0; i < values_.size(); i++) {
113 ALOGD("[%d] %" PRId64 "", i, values_[i]);
114 }
115 ALOGD("enums.size(%zu)", enums_.size());
116 uint32_t i = 0;
117 for (auto const &it : enums_) {
118 ALOGD("[%d] %s %" PRId64 "", i++, it.name_.c_str(), it.value_);
119 }
120 }
121
isImmutable() const122 bool DrmProperty::isImmutable() const {
123 return id_ && (flags_ & DRM_MODE_PROP_IMMUTABLE);
124 }
125
isRange() const126 bool DrmProperty::isRange() const {
127 return id_ && (flags_ & DRM_MODE_PROP_RANGE);
128 }
129
isSignedRange() const130 bool DrmProperty::isSignedRange() const {
131 return (flags_ & DRM_MODE_PROP_EXTENDED_TYPE) == DRM_MODE_PROP_SIGNED_RANGE;
132 }
133
isBitmask() const134 bool DrmProperty::isBitmask() const {
135 return id_ && (flags_ & DRM_MODE_PROP_BITMASK);
136 }
137
rangeMin() const138 std::tuple<int, uint64_t> DrmProperty::rangeMin() const {
139 if (!isRange())
140 return std::make_tuple(-EINVAL, 0);
141 if (values_.size() < 1)
142 return std::make_tuple(-ENOENT, 0);
143
144 return std::make_tuple(0, values_[0]);
145 }
146
rangeMax() const147 std::tuple<int, uint64_t> DrmProperty::rangeMax() const {
148 if (!isRange())
149 return std::make_tuple(-EINVAL, 0);
150 if (values_.size() < 2)
151 return std::make_tuple(-ENOENT, 0);
152
153 return std::make_tuple(0, values_[1]);
154 }
155
getEnumValueWithName(std::string name) const156 std::tuple<uint64_t, int> DrmProperty::getEnumValueWithName(std::string name) const {
157 for (auto it : enums_) {
158 if (it.name_.compare(name) == 0) {
159 return std::make_tuple(it.value_, 0);
160 }
161 }
162
163 return std::make_tuple(UINT64_MAX, -EINVAL);
164 }
165
validateChange(uint64_t value) const166 bool DrmProperty::validateChange(uint64_t value) const {
167 if (isImmutable()) {
168 ALOGE("%s: %s is immutable drm property (%zu)", __func__, name().c_str());
169 return false;
170 } else if (isRange()) {
171 if (value < values_[0] || value > values_[1]) {
172 ALOGE("%s: range property %s set to %" PRIu64 " is invalid [%" PRIu64 "-%" PRIu64 "]",
173 __func__, name().c_str(), value, values_[0], values_[1]);
174 return false;
175 }
176 } else if (isSignedRange()) {
177 int64_t svalue = U642I64(value);
178
179 if (svalue < U642I64(values_[0]) || svalue > U642I64(values_[1])) {
180 ALOGE("%s: signed property %s set to %" PRIi64 " is invalid [%" PRIi64 "-%" PRIi64 "]",
181 __func__, name().c_str(), svalue, U642I64(values_[0]), U642I64(values_[1]));
182 return false;
183 }
184 } else if (isBitmask()) {
185 uint64_t valid_mask = 0;
186
187 for (auto i = 0; i < values_.size(); i++) {
188 valid_mask |= (1ULL << values_[i]);
189 }
190 if (value & ~valid_mask) {
191 ALOGE("%s: bitmask property %s set to 0x%" PRIx64 " is invalid [0x%" PRIx64 "]", __func__,
192 name().c_str(), value, valid_mask);
193 return false;
194 }
195 }
196
197 return true;
198 }
199
updateValue(uint64_t value)200 void DrmProperty::updateValue(uint64_t value) {
201 value_ = value;
202 }
203
halToDrmEnum(const uint32_t halData,const MapHal2DrmEnum & drmEnums)204 std::tuple<uint64_t, int> DrmEnumParser::halToDrmEnum(const uint32_t halData,
205 const MapHal2DrmEnum& drmEnums) {
206 auto it = drmEnums.find(halData);
207 if (it != drmEnums.end()) {
208 return std::make_tuple(it->second, NO_ERROR);
209 } else {
210 ALOGE("%s: Failed to find standard enum(%d)", __func__, halData);
211 return std::make_tuple(0, -EINVAL);
212 }
213 }
214
parseEnums(const DrmProperty & property,const std::vector<std::pair<uint32_t,const char * >> & enums,MapHal2DrmEnum & out_enums)215 void DrmEnumParser::parseEnums(const DrmProperty &property,
216 const std::vector<std::pair<uint32_t, const char *>> &enums,
217 MapHal2DrmEnum& out_enums) {
218 uint64_t value;
219 int err;
220 for (auto &e : enums) {
221 std::tie(value, err) = property.getEnumValueWithName(e.second);
222 if (err) {
223 ALOGE("%s: Fail to find enum value with name %s", __func__, e.second);
224 } else {
225 out_enums[e.first] = value;
226 }
227 }
228 }
229
230 } // namespace android
231