1c29fa5a6Sopenharmony_ci/* 2c29fa5a6Sopenharmony_ci * Copyright (c) 2023-2024 Huawei Device Co., Ltd. 3c29fa5a6Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4c29fa5a6Sopenharmony_ci * you may not use this file except in compliance with the License. 5c29fa5a6Sopenharmony_ci * You may obtain a copy of the License at 6c29fa5a6Sopenharmony_ci * 7c29fa5a6Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8c29fa5a6Sopenharmony_ci * 9c29fa5a6Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10c29fa5a6Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11c29fa5a6Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12c29fa5a6Sopenharmony_ci * See the License for the specific language governing permissions and 13c29fa5a6Sopenharmony_ci * limitations under the License. 14c29fa5a6Sopenharmony_ci */ 15c29fa5a6Sopenharmony_ci 16c29fa5a6Sopenharmony_ci#include <algorithm> 17c29fa5a6Sopenharmony_ci#include <cerrno> 18c29fa5a6Sopenharmony_ci#include <climits> 19c29fa5a6Sopenharmony_ci#include <cstring> 20c29fa5a6Sopenharmony_ci#include <fstream> 21c29fa5a6Sopenharmony_ci#include <iostream> 22c29fa5a6Sopenharmony_ci#include <iterator> 23c29fa5a6Sopenharmony_ci#include <optional> 24c29fa5a6Sopenharmony_ci#include <sstream> 25c29fa5a6Sopenharmony_ci#include <string> 26c29fa5a6Sopenharmony_ci#include <unordered_map> 27c29fa5a6Sopenharmony_ci#include <vector> 28c29fa5a6Sopenharmony_ci 29c29fa5a6Sopenharmony_ci#include <unistd.h> 30c29fa5a6Sopenharmony_ci 31c29fa5a6Sopenharmony_ci#include <libudev.h> 32c29fa5a6Sopenharmony_ci#include <linux/input.h> 33c29fa5a6Sopenharmony_ci 34c29fa5a6Sopenharmony_ci#include "mmi_log.h" 35c29fa5a6Sopenharmony_ci 36c29fa5a6Sopenharmony_ci#undef MMI_LOG_DOMAIN 37c29fa5a6Sopenharmony_ci#define MMI_LOG_DOMAIN MMI_LOG_SERVER 38c29fa5a6Sopenharmony_ci#undef MMI_LOG_TAG 39c29fa5a6Sopenharmony_ci#define MMI_LOG_TAG "MmiLibudev" 40c29fa5a6Sopenharmony_ci 41c29fa5a6Sopenharmony_ciusing namespace std::literals; 42c29fa5a6Sopenharmony_cinamespace { 43c29fa5a6Sopenharmony_ciconstexpr int UTIL_PATH_SIZE { 1024 }; 44c29fa5a6Sopenharmony_ciconstexpr int UTIL_LINE_SIZE { 16384 }; 45c29fa5a6Sopenharmony_ci 46c29fa5a6Sopenharmony_cibool StartsWith(std::string_view str, std::string_view prefix) 47c29fa5a6Sopenharmony_ci{ 48c29fa5a6Sopenharmony_ci return str.size() >= prefix.size() && str.substr(0, prefix.size()) == prefix; 49c29fa5a6Sopenharmony_ci} 50c29fa5a6Sopenharmony_ci 51c29fa5a6Sopenharmony_cibool ChopTail(std::string_view &str, char sep) 52c29fa5a6Sopenharmony_ci{ 53c29fa5a6Sopenharmony_ci auto pos = str.rfind(sep); 54c29fa5a6Sopenharmony_ci if (pos == std::string_view::npos) { 55c29fa5a6Sopenharmony_ci return false; 56c29fa5a6Sopenharmony_ci } 57c29fa5a6Sopenharmony_ci str.remove_suffix(str.size() - pos); 58c29fa5a6Sopenharmony_ci return true; 59c29fa5a6Sopenharmony_ci} 60c29fa5a6Sopenharmony_ci 61c29fa5a6Sopenharmony_cistd::string ResolveSymLink(const std::string &syspath) 62c29fa5a6Sopenharmony_ci{ 63c29fa5a6Sopenharmony_ci constexpr auto backStr = "../"sv; 64c29fa5a6Sopenharmony_ci char linkTarget[UTIL_PATH_SIZE]; 65c29fa5a6Sopenharmony_ci 66c29fa5a6Sopenharmony_ci ssize_t len = readlink(syspath.c_str(), linkTarget, sizeof(linkTarget)); 67c29fa5a6Sopenharmony_ci if (len <= 0 || len == static_cast<ssize_t>(sizeof(linkTarget))) { 68c29fa5a6Sopenharmony_ci return syspath; 69c29fa5a6Sopenharmony_ci } 70c29fa5a6Sopenharmony_ci 71c29fa5a6Sopenharmony_ci std::string_view tail{ linkTarget, len }; 72c29fa5a6Sopenharmony_ci int32_t back = 0; 73c29fa5a6Sopenharmony_ci for (; StartsWith(tail, backStr); back++) { 74c29fa5a6Sopenharmony_ci tail.remove_prefix(backStr.size()); 75c29fa5a6Sopenharmony_ci } 76c29fa5a6Sopenharmony_ci 77c29fa5a6Sopenharmony_ci std::string_view base = syspath; 78c29fa5a6Sopenharmony_ci for (int32_t i = 0; i <= back; i++) { 79c29fa5a6Sopenharmony_ci if (!ChopTail(base, '/')) { 80c29fa5a6Sopenharmony_ci return syspath; 81c29fa5a6Sopenharmony_ci } 82c29fa5a6Sopenharmony_ci } 83c29fa5a6Sopenharmony_ci 84c29fa5a6Sopenharmony_ci return std::string{ base }.append("/").append(tail); 85c29fa5a6Sopenharmony_ci} 86c29fa5a6Sopenharmony_ci 87c29fa5a6Sopenharmony_cistd::optional<std::string> GetLinkValue(const std::string &slink, const std::string &syspath) 88c29fa5a6Sopenharmony_ci{ 89c29fa5a6Sopenharmony_ci auto path = syspath + "/" + slink; 90c29fa5a6Sopenharmony_ci 91c29fa5a6Sopenharmony_ci char target[UTIL_PATH_SIZE]; 92c29fa5a6Sopenharmony_ci ssize_t len = readlink(path.c_str(), target, sizeof(target)); 93c29fa5a6Sopenharmony_ci if (len <= 0 || len == static_cast<ssize_t>(sizeof(target))) { 94c29fa5a6Sopenharmony_ci MMI_HILOGE("Failed to read link"); 95c29fa5a6Sopenharmony_ci return std::nullopt; 96c29fa5a6Sopenharmony_ci } 97c29fa5a6Sopenharmony_ci 98c29fa5a6Sopenharmony_ci std::string_view result{ target, len }; 99c29fa5a6Sopenharmony_ci auto pos = result.rfind('/'); 100c29fa5a6Sopenharmony_ci if (pos == std::string_view::npos) { 101c29fa5a6Sopenharmony_ci MMI_HILOGE("Failed to get link value"); 102c29fa5a6Sopenharmony_ci return std::nullopt; 103c29fa5a6Sopenharmony_ci } 104c29fa5a6Sopenharmony_ci return std::string{ result.substr(pos + 1) }; 105c29fa5a6Sopenharmony_ci} 106c29fa5a6Sopenharmony_ci 107c29fa5a6Sopenharmony_ciclass BitVector { 108c29fa5a6Sopenharmony_cipublic: 109c29fa5a6Sopenharmony_ci // This type depends on kernel definition 110c29fa5a6Sopenharmony_ci using val_t = unsigned long; 111c29fa5a6Sopenharmony_ci 112c29fa5a6Sopenharmony_ci // Input string is hexadecimal 64-bit numbers separated by spaces with high bit number first 113c29fa5a6Sopenharmony_ci explicit BitVector(const std::string &str) 114c29fa5a6Sopenharmony_ci { 115c29fa5a6Sopenharmony_ci std::istringstream ss{ str }; 116c29fa5a6Sopenharmony_ci ss >> std::hex; 117c29fa5a6Sopenharmony_ci std::copy(std::istream_iterator<val_t>(ss), std::istream_iterator<val_t>(), std::back_inserter(bits_)); 118c29fa5a6Sopenharmony_ci // Since numbers in string starts with high number we need to reverse vector to count numbers from low to high 119c29fa5a6Sopenharmony_ci std::reverse(bits_.begin(), bits_.end()); 120c29fa5a6Sopenharmony_ci } 121c29fa5a6Sopenharmony_ci 122c29fa5a6Sopenharmony_ci [[nodiscard]] bool CheckBit(size_t idx) const 123c29fa5a6Sopenharmony_ci { 124c29fa5a6Sopenharmony_ci auto vidx = idx / (sizeof(val_t) * CHAR_BIT); 125c29fa5a6Sopenharmony_ci auto bidx = idx % (sizeof(val_t) * CHAR_BIT); 126c29fa5a6Sopenharmony_ci if (vidx >= bits_.size()) { 127c29fa5a6Sopenharmony_ci return false; 128c29fa5a6Sopenharmony_ci } 129c29fa5a6Sopenharmony_ci return (bits_[vidx] & (1ULL << bidx)) != 0; 130c29fa5a6Sopenharmony_ci } 131c29fa5a6Sopenharmony_ci 132c29fa5a6Sopenharmony_ciprivate: 133c29fa5a6Sopenharmony_ci std::vector<val_t> bits_; 134c29fa5a6Sopenharmony_ci}; 135c29fa5a6Sopenharmony_ci} // namespace 136c29fa5a6Sopenharmony_ci 137c29fa5a6Sopenharmony_cistruct udev {}; 138c29fa5a6Sopenharmony_ci 139c29fa5a6Sopenharmony_cistruct udev_device { 140c29fa5a6Sopenharmony_cipublic: 141c29fa5a6Sopenharmony_ci // Not copyable and not movable 142c29fa5a6Sopenharmony_ci udev_device(udev_device &) = delete; 143c29fa5a6Sopenharmony_ci udev_device(udev_device &&) = delete; 144c29fa5a6Sopenharmony_ci udev_device &operator = (udev_device &) = delete; 145c29fa5a6Sopenharmony_ci udev_device &operator = (udev_device &&) = delete; 146c29fa5a6Sopenharmony_ci 147c29fa5a6Sopenharmony_ci static udev_device *NewFromSyspath(const std::string &syspathParam) 148c29fa5a6Sopenharmony_ci { 149c29fa5a6Sopenharmony_ci // path starts in sys 150c29fa5a6Sopenharmony_ci if (!StartsWith(syspathParam, "/sys/") || syspathParam.back() == '/') { 151c29fa5a6Sopenharmony_ci errno = EINVAL; 152c29fa5a6Sopenharmony_ci return nullptr; 153c29fa5a6Sopenharmony_ci } 154c29fa5a6Sopenharmony_ci 155c29fa5a6Sopenharmony_ci // resolve possible symlink to real path 156c29fa5a6Sopenharmony_ci std::string path = ResolveSymLink(syspathParam); 157c29fa5a6Sopenharmony_ci if (StartsWith(path, "/sys/devices/")) { 158c29fa5a6Sopenharmony_ci // all "devices" require a "uevent" file 159c29fa5a6Sopenharmony_ci struct stat statbuf; 160c29fa5a6Sopenharmony_ci std::string filename = path + "/uevent"; 161c29fa5a6Sopenharmony_ci if (stat(filename.c_str(), &statbuf) != 0) { 162c29fa5a6Sopenharmony_ci return nullptr; 163c29fa5a6Sopenharmony_ci } 164c29fa5a6Sopenharmony_ci } else { 165c29fa5a6Sopenharmony_ci return nullptr; 166c29fa5a6Sopenharmony_ci } 167c29fa5a6Sopenharmony_ci 168c29fa5a6Sopenharmony_ci auto *inst = new udev_device; 169c29fa5a6Sopenharmony_ci inst->SetSyspath(std::move(path)); 170c29fa5a6Sopenharmony_ci 171c29fa5a6Sopenharmony_ci return inst; 172c29fa5a6Sopenharmony_ci } 173c29fa5a6Sopenharmony_ci 174c29fa5a6Sopenharmony_ci static udev_device *NewFromDevnum(char type, dev_t devnum) 175c29fa5a6Sopenharmony_ci { 176c29fa5a6Sopenharmony_ci const char *typeStr = nullptr; 177c29fa5a6Sopenharmony_ci 178c29fa5a6Sopenharmony_ci if (type == 'b') { 179c29fa5a6Sopenharmony_ci typeStr = "block"; 180c29fa5a6Sopenharmony_ci } else if (type == 'c') { 181c29fa5a6Sopenharmony_ci typeStr = "char"; 182c29fa5a6Sopenharmony_ci } else { 183c29fa5a6Sopenharmony_ci MMI_HILOGE("Param invalid"); 184c29fa5a6Sopenharmony_ci errno = EINVAL; 185c29fa5a6Sopenharmony_ci return nullptr; 186c29fa5a6Sopenharmony_ci } 187c29fa5a6Sopenharmony_ci 188c29fa5a6Sopenharmony_ci // use /sys/dev/{block,char}/<maj>:<min> link 189c29fa5a6Sopenharmony_ci auto majStr = std::to_string(major(devnum)); 190c29fa5a6Sopenharmony_ci auto minStr = std::to_string(minor(devnum)); 191c29fa5a6Sopenharmony_ci return NewFromSyspath("/sys/dev/"s + typeStr + "/" + majStr + ":" + minStr); 192c29fa5a6Sopenharmony_ci } 193c29fa5a6Sopenharmony_ci 194c29fa5a6Sopenharmony_ci void Ref() 195c29fa5a6Sopenharmony_ci { 196c29fa5a6Sopenharmony_ci refcount++; 197c29fa5a6Sopenharmony_ci } 198c29fa5a6Sopenharmony_ci 199c29fa5a6Sopenharmony_ci void Unref() 200c29fa5a6Sopenharmony_ci { 201c29fa5a6Sopenharmony_ci if (--refcount <= 0) { 202c29fa5a6Sopenharmony_ci delete this; 203c29fa5a6Sopenharmony_ci } 204c29fa5a6Sopenharmony_ci } 205c29fa5a6Sopenharmony_ci 206c29fa5a6Sopenharmony_ci udev_device *GetParent() 207c29fa5a6Sopenharmony_ci { 208c29fa5a6Sopenharmony_ci if (!parentDevice_.has_value()) { 209c29fa5a6Sopenharmony_ci parentDevice_ = NewFromChild(this); 210c29fa5a6Sopenharmony_ci } 211c29fa5a6Sopenharmony_ci return *parentDevice_; 212c29fa5a6Sopenharmony_ci } 213c29fa5a6Sopenharmony_ci 214c29fa5a6Sopenharmony_ci const std::string &GetSyspath() const 215c29fa5a6Sopenharmony_ci { 216c29fa5a6Sopenharmony_ci return syspath; 217c29fa5a6Sopenharmony_ci } 218c29fa5a6Sopenharmony_ci 219c29fa5a6Sopenharmony_ci const std::string &GetSysname() const 220c29fa5a6Sopenharmony_ci { 221c29fa5a6Sopenharmony_ci return sysname; 222c29fa5a6Sopenharmony_ci } 223c29fa5a6Sopenharmony_ci 224c29fa5a6Sopenharmony_ci const std::string &GetDevnode() 225c29fa5a6Sopenharmony_ci { 226c29fa5a6Sopenharmony_ci return GetProperty("DEVNAME"); 227c29fa5a6Sopenharmony_ci } 228c29fa5a6Sopenharmony_ci 229c29fa5a6Sopenharmony_ci bool IsInitialized() 230c29fa5a6Sopenharmony_ci { 231c29fa5a6Sopenharmony_ci if (!ueventLoaded) { 232c29fa5a6Sopenharmony_ci ReadUeventFile(); 233c29fa5a6Sopenharmony_ci } 234c29fa5a6Sopenharmony_ci return ueventLoaded; 235c29fa5a6Sopenharmony_ci } 236c29fa5a6Sopenharmony_ci 237c29fa5a6Sopenharmony_ci udev_device *GetParentWithSubsystem(const std::string &subsystem) 238c29fa5a6Sopenharmony_ci { 239c29fa5a6Sopenharmony_ci udev_device *parent = GetParent(); 240c29fa5a6Sopenharmony_ci while (parent != nullptr) { 241c29fa5a6Sopenharmony_ci auto parentSubsystem = parent->GetSubsystem(); 242c29fa5a6Sopenharmony_ci if (parentSubsystem.has_value() && parentSubsystem.value() == subsystem) { 243c29fa5a6Sopenharmony_ci break; 244c29fa5a6Sopenharmony_ci } 245c29fa5a6Sopenharmony_ci parent = parent->GetParent(); 246c29fa5a6Sopenharmony_ci } 247c29fa5a6Sopenharmony_ci 248c29fa5a6Sopenharmony_ci if (parent == nullptr) { 249c29fa5a6Sopenharmony_ci errno = ENOENT; 250c29fa5a6Sopenharmony_ci } 251c29fa5a6Sopenharmony_ci return parent; 252c29fa5a6Sopenharmony_ci } 253c29fa5a6Sopenharmony_ci 254c29fa5a6Sopenharmony_ci bool HasProperty(const std::string &key) 255c29fa5a6Sopenharmony_ci { 256c29fa5a6Sopenharmony_ci if (!ueventLoaded) { 257c29fa5a6Sopenharmony_ci ReadUeventFile(); 258c29fa5a6Sopenharmony_ci } 259c29fa5a6Sopenharmony_ci return property_.find(key) != property_.end(); 260c29fa5a6Sopenharmony_ci } 261c29fa5a6Sopenharmony_ci 262c29fa5a6Sopenharmony_ci const std::string &GetProperty(const std::string &key) 263c29fa5a6Sopenharmony_ci { 264c29fa5a6Sopenharmony_ci if (!ueventLoaded) { 265c29fa5a6Sopenharmony_ci ReadUeventFile(); 266c29fa5a6Sopenharmony_ci } 267c29fa5a6Sopenharmony_ci return property_[key]; 268c29fa5a6Sopenharmony_ci } 269c29fa5a6Sopenharmony_ci 270c29fa5a6Sopenharmony_ciprivate: 271c29fa5a6Sopenharmony_ci udev_device() = default; 272c29fa5a6Sopenharmony_ci 273c29fa5a6Sopenharmony_ci ~udev_device() 274c29fa5a6Sopenharmony_ci { 275c29fa5a6Sopenharmony_ci if (parentDevice_.has_value() && parentDevice_.value() != nullptr) { 276c29fa5a6Sopenharmony_ci parentDevice_.value()->Unref(); 277c29fa5a6Sopenharmony_ci } 278c29fa5a6Sopenharmony_ci } 279c29fa5a6Sopenharmony_ci 280c29fa5a6Sopenharmony_ci static udev_device *NewFromChild(udev_device *child) 281c29fa5a6Sopenharmony_ci { 282c29fa5a6Sopenharmony_ci std::string_view path = child->GetSyspath(); 283c29fa5a6Sopenharmony_ci 284c29fa5a6Sopenharmony_ci while (true) { 285c29fa5a6Sopenharmony_ci if (!ChopTail(path, '/')) { 286c29fa5a6Sopenharmony_ci break; 287c29fa5a6Sopenharmony_ci } 288c29fa5a6Sopenharmony_ci udev_device *parent = NewFromSyspath(std::string{ path }); 289c29fa5a6Sopenharmony_ci if (parent != nullptr) { 290c29fa5a6Sopenharmony_ci return parent; 291c29fa5a6Sopenharmony_ci } 292c29fa5a6Sopenharmony_ci } 293c29fa5a6Sopenharmony_ci 294c29fa5a6Sopenharmony_ci return nullptr; 295c29fa5a6Sopenharmony_ci } 296c29fa5a6Sopenharmony_ci 297c29fa5a6Sopenharmony_ci void SetSyspath(std::string newSyspath) 298c29fa5a6Sopenharmony_ci { 299c29fa5a6Sopenharmony_ci syspath = std::move(newSyspath); 300c29fa5a6Sopenharmony_ci 301c29fa5a6Sopenharmony_ci AddProperty("DEVPATH", syspath.substr(0, "/sys"sv.size())); 302c29fa5a6Sopenharmony_ci 303c29fa5a6Sopenharmony_ci auto pos = syspath.rfind('/'); 304c29fa5a6Sopenharmony_ci if (pos == std::string::npos) { 305c29fa5a6Sopenharmony_ci return; 306c29fa5a6Sopenharmony_ci } 307c29fa5a6Sopenharmony_ci sysname = syspath.substr(pos + 1); 308c29fa5a6Sopenharmony_ci 309c29fa5a6Sopenharmony_ci // some devices have '!' in their name, change that to '/' 310c29fa5a6Sopenharmony_ci for (char &c : sysname) { 311c29fa5a6Sopenharmony_ci if (c == '!') { 312c29fa5a6Sopenharmony_ci c = '/'; 313c29fa5a6Sopenharmony_ci } 314c29fa5a6Sopenharmony_ci } 315c29fa5a6Sopenharmony_ci } 316c29fa5a6Sopenharmony_ci 317c29fa5a6Sopenharmony_ci void AddPropertyFromString(const std::string &line) 318c29fa5a6Sopenharmony_ci { 319c29fa5a6Sopenharmony_ci auto pos = line.find('='); 320c29fa5a6Sopenharmony_ci if (pos == std::string::npos) { 321c29fa5a6Sopenharmony_ci return; 322c29fa5a6Sopenharmony_ci } 323c29fa5a6Sopenharmony_ci std::string key = line.substr(0, pos); 324c29fa5a6Sopenharmony_ci if (key == "DEVNAME") { 325c29fa5a6Sopenharmony_ci SetDevnode(line.substr(pos + 1)); 326c29fa5a6Sopenharmony_ci return; 327c29fa5a6Sopenharmony_ci } 328c29fa5a6Sopenharmony_ci AddProperty(std::move(key), line.substr(pos + 1)); 329c29fa5a6Sopenharmony_ci } 330c29fa5a6Sopenharmony_ci 331c29fa5a6Sopenharmony_ci void ReadUeventFile() 332c29fa5a6Sopenharmony_ci { 333c29fa5a6Sopenharmony_ci if (ueventLoaded) { 334c29fa5a6Sopenharmony_ci return; 335c29fa5a6Sopenharmony_ci } 336c29fa5a6Sopenharmony_ci 337c29fa5a6Sopenharmony_ci auto filename = syspath + "/uevent"; 338c29fa5a6Sopenharmony_ci char realPath[PATH_MAX] = {}; 339c29fa5a6Sopenharmony_ci CHKPV(realpath(filename.c_str(), realPath)); 340c29fa5a6Sopenharmony_ci std::ifstream f(realPath, std::ios_base::in); 341c29fa5a6Sopenharmony_ci if (!f.is_open()) { 342c29fa5a6Sopenharmony_ci MMI_HILOGE("ReadUeventFile(): path:%{private}s, error:%{public}s", realPath, std::strerror(errno)); 343c29fa5a6Sopenharmony_ci return; 344c29fa5a6Sopenharmony_ci } 345c29fa5a6Sopenharmony_ci ueventLoaded = true; 346c29fa5a6Sopenharmony_ci 347c29fa5a6Sopenharmony_ci char line[UTIL_LINE_SIZE]; 348c29fa5a6Sopenharmony_ci while (f.getline(line, sizeof(line))) { 349c29fa5a6Sopenharmony_ci AddPropertyFromString(line); 350c29fa5a6Sopenharmony_ci } 351c29fa5a6Sopenharmony_ci 352c29fa5a6Sopenharmony_ci CheckInputProperties(); 353c29fa5a6Sopenharmony_ci } 354c29fa5a6Sopenharmony_ci 355c29fa5a6Sopenharmony_ci bool CheckAccel(const BitVector &ev, const BitVector &abs, const BitVector &prop) 356c29fa5a6Sopenharmony_ci { 357c29fa5a6Sopenharmony_ci bool hasKeys = ev.CheckBit(EV_KEY); 358c29fa5a6Sopenharmony_ci bool has3dCoordinates = abs.CheckBit(ABS_X) && abs.CheckBit(ABS_Y) && abs.CheckBit(ABS_Z); 359c29fa5a6Sopenharmony_ci bool isAccelerometer = prop.CheckBit(INPUT_PROP_ACCELEROMETER); 360c29fa5a6Sopenharmony_ci 361c29fa5a6Sopenharmony_ci if (!hasKeys && has3dCoordinates) { 362c29fa5a6Sopenharmony_ci isAccelerometer = true; 363c29fa5a6Sopenharmony_ci } 364c29fa5a6Sopenharmony_ci 365c29fa5a6Sopenharmony_ci if (isAccelerometer) { 366c29fa5a6Sopenharmony_ci SetInputProperty("ID_INPUT_ACCELEROMETER"); 367c29fa5a6Sopenharmony_ci } 368c29fa5a6Sopenharmony_ci return isAccelerometer; 369c29fa5a6Sopenharmony_ci } 370c29fa5a6Sopenharmony_ci 371c29fa5a6Sopenharmony_ci bool HasJoystickAxesOrButtons(const BitVector &abs, const BitVector &key) 372c29fa5a6Sopenharmony_ci { 373c29fa5a6Sopenharmony_ci bool hasJoystickAxesOrButtons = false; 374c29fa5a6Sopenharmony_ci // Some mouses have so much buttons that they overflow in joystick range, ignore them 375c29fa5a6Sopenharmony_ci if (!key.CheckBit(BTN_JOYSTICK - 1)) { 376c29fa5a6Sopenharmony_ci for (int32_t button = BTN_JOYSTICK; button < BTN_DIGI && !hasJoystickAxesOrButtons; button++) { 377c29fa5a6Sopenharmony_ci hasJoystickAxesOrButtons = key.CheckBit(button); 378c29fa5a6Sopenharmony_ci } 379c29fa5a6Sopenharmony_ci for (int32_t button = BTN_TRIGGER_HAPPY1; button <= BTN_TRIGGER_HAPPY40 && !hasJoystickAxesOrButtons; 380c29fa5a6Sopenharmony_ci button++) { 381c29fa5a6Sopenharmony_ci hasJoystickAxesOrButtons = key.CheckBit(button); 382c29fa5a6Sopenharmony_ci } 383c29fa5a6Sopenharmony_ci for (int32_t button = BTN_DPAD_UP; button <= BTN_DPAD_RIGHT && !hasJoystickAxesOrButtons; button++) { 384c29fa5a6Sopenharmony_ci hasJoystickAxesOrButtons = key.CheckBit(button); 385c29fa5a6Sopenharmony_ci } 386c29fa5a6Sopenharmony_ci } 387c29fa5a6Sopenharmony_ci for (int32_t axis = ABS_RX; axis < ABS_PRESSURE && !hasJoystickAxesOrButtons; axis++) { 388c29fa5a6Sopenharmony_ci hasJoystickAxesOrButtons = abs.CheckBit(axis); 389c29fa5a6Sopenharmony_ci } 390c29fa5a6Sopenharmony_ci return hasJoystickAxesOrButtons; 391c29fa5a6Sopenharmony_ci } 392c29fa5a6Sopenharmony_ci 393c29fa5a6Sopenharmony_ci bool CheckPointingStick(const BitVector &prop) 394c29fa5a6Sopenharmony_ci { 395c29fa5a6Sopenharmony_ci if (prop.CheckBit(INPUT_PROP_POINTING_STICK)) { 396c29fa5a6Sopenharmony_ci SetInputProperty("ID_INPUT_POINTINGSTICK"); 397c29fa5a6Sopenharmony_ci return true; 398c29fa5a6Sopenharmony_ci } 399c29fa5a6Sopenharmony_ci return false; 400c29fa5a6Sopenharmony_ci } 401c29fa5a6Sopenharmony_ci 402c29fa5a6Sopenharmony_ci void CheckAndSetProp(std::string prop, const bool &flag) 403c29fa5a6Sopenharmony_ci { 404c29fa5a6Sopenharmony_ci if (flag) { 405c29fa5a6Sopenharmony_ci SetInputProperty(prop); 406c29fa5a6Sopenharmony_ci MMI_HILOGD("device has prop with %{public}s", prop.c_str()); 407c29fa5a6Sopenharmony_ci } 408c29fa5a6Sopenharmony_ci } 409c29fa5a6Sopenharmony_ci 410c29fa5a6Sopenharmony_ci void CheckMouseButton(const BitVector &key, bool &flag) 411c29fa5a6Sopenharmony_ci { 412c29fa5a6Sopenharmony_ci for (int32_t button = BTN_MOUSE; button < BTN_JOYSTICK && !flag; button++) { 413c29fa5a6Sopenharmony_ci flag = key.CheckBit(button); 414c29fa5a6Sopenharmony_ci } 415c29fa5a6Sopenharmony_ci } 416c29fa5a6Sopenharmony_ci 417c29fa5a6Sopenharmony_ci void UpdateProByKey(const BitVector &key, const bool &isDirect, bool &probablyTablet, bool &probablyTouchpad, 418c29fa5a6Sopenharmony_ci bool &probablyTouchscreen) 419c29fa5a6Sopenharmony_ci { 420c29fa5a6Sopenharmony_ci probablyTablet = key.CheckBit(BTN_STYLUS) || key.CheckBit(BTN_TOOL_PEN); 421c29fa5a6Sopenharmony_ci probablyTouchpad = key.CheckBit(BTN_TOOL_FINGER) && !key.CheckBit(BTN_TOOL_PEN) && !isDirect; 422c29fa5a6Sopenharmony_ci probablyTouchscreen = key.CheckBit(BTN_TOUCH) && isDirect; 423c29fa5a6Sopenharmony_ci } 424c29fa5a6Sopenharmony_ci 425c29fa5a6Sopenharmony_ci bool CheckMtCoordinates(const BitVector &abs) 426c29fa5a6Sopenharmony_ci { 427c29fa5a6Sopenharmony_ci bool hasMtCoordinates = abs.CheckBit(ABS_MT_POSITION_X) && abs.CheckBit(ABS_MT_POSITION_Y); 428c29fa5a6Sopenharmony_ci /* unset hasMtCoordinates if devices claims to have all abs axis */ 429c29fa5a6Sopenharmony_ci if (hasMtCoordinates && abs.CheckBit(ABS_MT_SLOT) && abs.CheckBit(ABS_MT_SLOT - 1)) { 430c29fa5a6Sopenharmony_ci hasMtCoordinates = false; 431c29fa5a6Sopenharmony_ci } 432c29fa5a6Sopenharmony_ci return hasMtCoordinates; 433c29fa5a6Sopenharmony_ci } 434c29fa5a6Sopenharmony_ci 435c29fa5a6Sopenharmony_ci void UpdateProByStatus(const bool &isMouse, const bool &isTouchpad, const bool &isTouchscreen, 436c29fa5a6Sopenharmony_ci const bool &isJoystick, const bool &isTablet) 437c29fa5a6Sopenharmony_ci { 438c29fa5a6Sopenharmony_ci CheckAndSetProp("ID_INPUT_MOUSE", isMouse); 439c29fa5a6Sopenharmony_ci CheckAndSetProp("ID_INPUT_TOUCHPAD", isTouchpad); 440c29fa5a6Sopenharmony_ci CheckAndSetProp("ID_INPUT_TOUCHSCREEN", isTouchscreen); 441c29fa5a6Sopenharmony_ci CheckAndSetProp("ID_INPUT_JOYSTICK", isJoystick); 442c29fa5a6Sopenharmony_ci CheckAndSetProp("ID_INPUT_TABLET", isTablet); 443c29fa5a6Sopenharmony_ci } 444c29fa5a6Sopenharmony_ci 445c29fa5a6Sopenharmony_ci bool CheckPointers(const BitVector &ev, const BitVector &abs, const BitVector &key, const BitVector &rel, 446c29fa5a6Sopenharmony_ci const BitVector &prop) 447c29fa5a6Sopenharmony_ci { 448c29fa5a6Sopenharmony_ci bool isDirect = prop.CheckBit(INPUT_PROP_DIRECT); 449c29fa5a6Sopenharmony_ci bool hasAbsCoordinates = abs.CheckBit(ABS_X) && abs.CheckBit(ABS_Y); 450c29fa5a6Sopenharmony_ci bool hasRelCoordinates = ev.CheckBit(EV_REL) && rel.CheckBit(REL_X) && rel.CheckBit(REL_Y); 451c29fa5a6Sopenharmony_ci bool hasMtCoordinates = CheckMtCoordinates(abs); 452c29fa5a6Sopenharmony_ci 453c29fa5a6Sopenharmony_ci bool hasMouseButton = false; 454c29fa5a6Sopenharmony_ci CheckMouseButton(key, hasMouseButton); 455c29fa5a6Sopenharmony_ci 456c29fa5a6Sopenharmony_ci bool probablyTablet; 457c29fa5a6Sopenharmony_ci bool probablyTouchpad; 458c29fa5a6Sopenharmony_ci bool probablyTouchscreen; 459c29fa5a6Sopenharmony_ci UpdateProByKey(key, isDirect, probablyTablet, probablyTouchpad, probablyTouchscreen); 460c29fa5a6Sopenharmony_ci bool probablyJoystick = HasJoystickAxesOrButtons(abs, key); 461c29fa5a6Sopenharmony_ci 462c29fa5a6Sopenharmony_ci bool isTablet = false; 463c29fa5a6Sopenharmony_ci bool isMouse = false; 464c29fa5a6Sopenharmony_ci bool isTouchpad = false; 465c29fa5a6Sopenharmony_ci bool isTouchscreen = false; 466c29fa5a6Sopenharmony_ci bool isJoystick = false; 467c29fa5a6Sopenharmony_ci if (hasAbsCoordinates) { 468c29fa5a6Sopenharmony_ci if (probablyTablet) { 469c29fa5a6Sopenharmony_ci isTablet = true; 470c29fa5a6Sopenharmony_ci } else if (probablyTouchpad) { 471c29fa5a6Sopenharmony_ci isTouchpad = true; 472c29fa5a6Sopenharmony_ci } else if (hasMouseButton) { 473c29fa5a6Sopenharmony_ci /* This path is taken by VMware's USB mouse, which has 474c29fa5a6Sopenharmony_ci * absolute axes, but no touch/pressure button. */ 475c29fa5a6Sopenharmony_ci isMouse = true; 476c29fa5a6Sopenharmony_ci } else if (probablyTouchscreen) { 477c29fa5a6Sopenharmony_ci isTouchscreen = true; 478c29fa5a6Sopenharmony_ci } else { 479c29fa5a6Sopenharmony_ci isJoystick = probablyJoystick; 480c29fa5a6Sopenharmony_ci } 481c29fa5a6Sopenharmony_ci } else { 482c29fa5a6Sopenharmony_ci isJoystick = probablyJoystick; 483c29fa5a6Sopenharmony_ci } 484c29fa5a6Sopenharmony_ci 485c29fa5a6Sopenharmony_ci if (hasMtCoordinates) { 486c29fa5a6Sopenharmony_ci if (probablyTablet) { 487c29fa5a6Sopenharmony_ci isTablet = true; 488c29fa5a6Sopenharmony_ci } else if (probablyTouchpad) { 489c29fa5a6Sopenharmony_ci isTouchpad = true; 490c29fa5a6Sopenharmony_ci } else if (probablyTouchscreen) { 491c29fa5a6Sopenharmony_ci isTouchscreen = true; 492c29fa5a6Sopenharmony_ci } 493c29fa5a6Sopenharmony_ci } 494c29fa5a6Sopenharmony_ci 495c29fa5a6Sopenharmony_ci /* mouse buttons and no axis */ 496c29fa5a6Sopenharmony_ci if (!isTablet && !isTouchpad && !isJoystick && hasMouseButton && (hasRelCoordinates || !hasAbsCoordinates)) { 497c29fa5a6Sopenharmony_ci isMouse = true; 498c29fa5a6Sopenharmony_ci } 499c29fa5a6Sopenharmony_ci 500c29fa5a6Sopenharmony_ci UpdateProByStatus(isMouse, isTouchpad, isTouchscreen, isJoystick, isTablet); 501c29fa5a6Sopenharmony_ci 502c29fa5a6Sopenharmony_ci return isTablet || isMouse || isTouchpad || isTouchscreen || isJoystick || CheckPointingStick(prop); 503c29fa5a6Sopenharmony_ci } 504c29fa5a6Sopenharmony_ci 505c29fa5a6Sopenharmony_ci bool CheckKeys(const BitVector &ev, const BitVector &key) 506c29fa5a6Sopenharmony_ci { 507c29fa5a6Sopenharmony_ci if (!ev.CheckBit(EV_KEY)) { 508c29fa5a6Sopenharmony_ci return false; 509c29fa5a6Sopenharmony_ci } 510c29fa5a6Sopenharmony_ci 511c29fa5a6Sopenharmony_ci /* only consider KEY_* here, not BTN_* */ 512c29fa5a6Sopenharmony_ci bool found = false; 513c29fa5a6Sopenharmony_ci for (int32_t i = 0; i < BTN_MISC && !found; ++i) { 514c29fa5a6Sopenharmony_ci found = key.CheckBit(i); 515c29fa5a6Sopenharmony_ci } 516c29fa5a6Sopenharmony_ci /* If there are no keys in the lower block, check the higher blocks */ 517c29fa5a6Sopenharmony_ci for (int32_t i = KEY_OK; i < BTN_DPAD_UP && !found; ++i) { 518c29fa5a6Sopenharmony_ci found = key.CheckBit(i); 519c29fa5a6Sopenharmony_ci } 520c29fa5a6Sopenharmony_ci for (int32_t i = KEY_ALS_TOGGLE; i < BTN_TRIGGER_HAPPY && !found; ++i) { 521c29fa5a6Sopenharmony_ci found = key.CheckBit(i); 522c29fa5a6Sopenharmony_ci } 523c29fa5a6Sopenharmony_ci 524c29fa5a6Sopenharmony_ci if (found) { 525c29fa5a6Sopenharmony_ci SetInputProperty("ID_INPUT_KEY"); 526c29fa5a6Sopenharmony_ci } 527c29fa5a6Sopenharmony_ci 528c29fa5a6Sopenharmony_ci /* the first 32 bits are ESC, numbers, and Q to D; if we have all of 529c29fa5a6Sopenharmony_ci * those, consider it a full keyboard; do not test KEY_RESERVED, though */ 530c29fa5a6Sopenharmony_ci bool isKeyboard = true; 531c29fa5a6Sopenharmony_ci for (int32_t i = KEY_ESC; i < KEY_D && isKeyboard; i++) { 532c29fa5a6Sopenharmony_ci isKeyboard = key.CheckBit(i); 533c29fa5a6Sopenharmony_ci } 534c29fa5a6Sopenharmony_ci if (isKeyboard) { 535c29fa5a6Sopenharmony_ci SetInputProperty("ID_INPUT_KEYBOARD"); 536c29fa5a6Sopenharmony_ci } 537c29fa5a6Sopenharmony_ci 538c29fa5a6Sopenharmony_ci return found || isKeyboard; 539c29fa5a6Sopenharmony_ci } 540c29fa5a6Sopenharmony_ci 541c29fa5a6Sopenharmony_ci void SetInputProperty(std::string prop) 542c29fa5a6Sopenharmony_ci { 543c29fa5a6Sopenharmony_ci AddProperty("ID_INPUT", "1"); 544c29fa5a6Sopenharmony_ci AddProperty(std::move(prop), "1"); 545c29fa5a6Sopenharmony_ci } 546c29fa5a6Sopenharmony_ci 547c29fa5a6Sopenharmony_ci void CheckInputProperties() 548c29fa5a6Sopenharmony_ci { 549c29fa5a6Sopenharmony_ci BitVector ev{ GetProperty("EV") }; 550c29fa5a6Sopenharmony_ci BitVector abs{ GetProperty("ABS") }; 551c29fa5a6Sopenharmony_ci BitVector key{ GetProperty("KEY") }; 552c29fa5a6Sopenharmony_ci BitVector rel{ GetProperty("REL") }; 553c29fa5a6Sopenharmony_ci BitVector prop{ GetProperty("PROP") }; 554c29fa5a6Sopenharmony_ci 555c29fa5a6Sopenharmony_ci bool isPointer = CheckAccel(ev, abs, prop) || CheckPointers(ev, abs, key, rel, prop); 556c29fa5a6Sopenharmony_ci bool isKey = CheckKeys(ev, key); 557c29fa5a6Sopenharmony_ci /* Some evdev nodes have only a scrollwheel */ 558c29fa5a6Sopenharmony_ci if (!isPointer && !isKey && ev.CheckBit(EV_REL) && (rel.CheckBit(REL_WHEEL) || rel.CheckBit(REL_HWHEEL))) { 559c29fa5a6Sopenharmony_ci SetInputProperty("ID_INPUT_KEY"); 560c29fa5a6Sopenharmony_ci } 561c29fa5a6Sopenharmony_ci if (ev.CheckBit(EV_SW)) { 562c29fa5a6Sopenharmony_ci SetInputProperty("ID_INPUT_SWITCH"); 563c29fa5a6Sopenharmony_ci } 564c29fa5a6Sopenharmony_ci } 565c29fa5a6Sopenharmony_ci 566c29fa5a6Sopenharmony_ci void SetDevnode(std::string newDevnode) 567c29fa5a6Sopenharmony_ci { 568c29fa5a6Sopenharmony_ci if (newDevnode[0] != '/') { 569c29fa5a6Sopenharmony_ci newDevnode = "/dev/" + newDevnode; 570c29fa5a6Sopenharmony_ci } 571c29fa5a6Sopenharmony_ci AddProperty("DEVNAME", std::move(newDevnode)); 572c29fa5a6Sopenharmony_ci } 573c29fa5a6Sopenharmony_ci 574c29fa5a6Sopenharmony_ci void AddProperty(std::string key, std::string value) 575c29fa5a6Sopenharmony_ci { 576c29fa5a6Sopenharmony_ci property_[std::move(key)] = std::move(value); 577c29fa5a6Sopenharmony_ci } 578c29fa5a6Sopenharmony_ci 579c29fa5a6Sopenharmony_ci std::optional<std::string> GetSubsystem() 580c29fa5a6Sopenharmony_ci { 581c29fa5a6Sopenharmony_ci if (!subsystem_.has_value()) { 582c29fa5a6Sopenharmony_ci auto res = GetLinkValue("subsystem", syspath); 583c29fa5a6Sopenharmony_ci // read "subsystem" link 584c29fa5a6Sopenharmony_ci if (res.has_value()) { 585c29fa5a6Sopenharmony_ci SetSubsystem(std::move(*res)); 586c29fa5a6Sopenharmony_ci return subsystem_; 587c29fa5a6Sopenharmony_ci } 588c29fa5a6Sopenharmony_ci subsystem_ = ""; 589c29fa5a6Sopenharmony_ci } 590c29fa5a6Sopenharmony_ci return subsystem_; 591c29fa5a6Sopenharmony_ci } 592c29fa5a6Sopenharmony_ci 593c29fa5a6Sopenharmony_ci void SetSubsystem(std::string newSubsystem) 594c29fa5a6Sopenharmony_ci { 595c29fa5a6Sopenharmony_ci subsystem_ = newSubsystem; 596c29fa5a6Sopenharmony_ci AddProperty("SUBSYSTEM", std::move(newSubsystem)); 597c29fa5a6Sopenharmony_ci } 598c29fa5a6Sopenharmony_ci 599c29fa5a6Sopenharmony_ciprivate: 600c29fa5a6Sopenharmony_ci int refcount = 1; 601c29fa5a6Sopenharmony_ci std::string syspath; 602c29fa5a6Sopenharmony_ci std::string sysname; 603c29fa5a6Sopenharmony_ci 604c29fa5a6Sopenharmony_ci std::optional<udev_device *> parentDevice_; 605c29fa5a6Sopenharmony_ci std::optional<std::string> subsystem_; 606c29fa5a6Sopenharmony_ci 607c29fa5a6Sopenharmony_ci bool ueventLoaded = false; 608c29fa5a6Sopenharmony_ci std::unordered_map<std::string, std::string> property_; 609c29fa5a6Sopenharmony_ci}; 610c29fa5a6Sopenharmony_ci 611c29fa5a6Sopenharmony_ci// C-style interface 612c29fa5a6Sopenharmony_ci 613c29fa5a6Sopenharmony_ciudev *udev_new(void) 614c29fa5a6Sopenharmony_ci{ 615c29fa5a6Sopenharmony_ci static udev instance{}; 616c29fa5a6Sopenharmony_ci return &instance; 617c29fa5a6Sopenharmony_ci} 618c29fa5a6Sopenharmony_ci 619c29fa5a6Sopenharmony_ciudev *udev_unref([[maybe_unused]] udev *udev) 620c29fa5a6Sopenharmony_ci{ 621c29fa5a6Sopenharmony_ci return nullptr; 622c29fa5a6Sopenharmony_ci} 623c29fa5a6Sopenharmony_ci 624c29fa5a6Sopenharmony_ciudev_device *udev_device_ref(udev_device *device) 625c29fa5a6Sopenharmony_ci{ 626c29fa5a6Sopenharmony_ci CHKPP(device); 627c29fa5a6Sopenharmony_ci device->Ref(); 628c29fa5a6Sopenharmony_ci return device; 629c29fa5a6Sopenharmony_ci} 630c29fa5a6Sopenharmony_ci 631c29fa5a6Sopenharmony_ciudev_device *udev_device_unref(udev_device *device) 632c29fa5a6Sopenharmony_ci{ 633c29fa5a6Sopenharmony_ci CHKPP(device); 634c29fa5a6Sopenharmony_ci device->Unref(); 635c29fa5a6Sopenharmony_ci return nullptr; 636c29fa5a6Sopenharmony_ci} 637c29fa5a6Sopenharmony_ci 638c29fa5a6Sopenharmony_ciudev *udev_device_get_udev(udev_device *device) 639c29fa5a6Sopenharmony_ci{ 640c29fa5a6Sopenharmony_ci CHKPP(device); 641c29fa5a6Sopenharmony_ci return udev_new(); 642c29fa5a6Sopenharmony_ci} 643c29fa5a6Sopenharmony_ci 644c29fa5a6Sopenharmony_ciudev_device *udev_device_new_from_syspath(udev *udev, const char *syspath) 645c29fa5a6Sopenharmony_ci{ 646c29fa5a6Sopenharmony_ci if (udev == nullptr || syspath == nullptr) { 647c29fa5a6Sopenharmony_ci errno = EINVAL; 648c29fa5a6Sopenharmony_ci return nullptr; 649c29fa5a6Sopenharmony_ci } 650c29fa5a6Sopenharmony_ci return udev_device::NewFromSyspath(syspath); 651c29fa5a6Sopenharmony_ci} 652c29fa5a6Sopenharmony_ci 653c29fa5a6Sopenharmony_ciudev_device *udev_device_new_from_devnum(udev *udev, char type, dev_t devnum) 654c29fa5a6Sopenharmony_ci{ 655c29fa5a6Sopenharmony_ci if (udev == nullptr) { 656c29fa5a6Sopenharmony_ci errno = EINVAL; 657c29fa5a6Sopenharmony_ci return nullptr; 658c29fa5a6Sopenharmony_ci } 659c29fa5a6Sopenharmony_ci return udev_device::NewFromDevnum(type, devnum); 660c29fa5a6Sopenharmony_ci} 661c29fa5a6Sopenharmony_ci 662c29fa5a6Sopenharmony_ciudev_device *udev_device_get_parent(udev_device *device) 663c29fa5a6Sopenharmony_ci{ 664c29fa5a6Sopenharmony_ci if (device == nullptr) { 665c29fa5a6Sopenharmony_ci errno = EINVAL; 666c29fa5a6Sopenharmony_ci return nullptr; 667c29fa5a6Sopenharmony_ci } 668c29fa5a6Sopenharmony_ci return device->GetParent(); 669c29fa5a6Sopenharmony_ci} 670c29fa5a6Sopenharmony_ci 671c29fa5a6Sopenharmony_ciudev_device *udev_device_get_parent_with_subsystem_devtype(udev_device *device, const char *subsystem, 672c29fa5a6Sopenharmony_ci const char *devtype) 673c29fa5a6Sopenharmony_ci{ 674c29fa5a6Sopenharmony_ci CHKPP(device); 675c29fa5a6Sopenharmony_ci if (subsystem == nullptr) { 676c29fa5a6Sopenharmony_ci errno = EINVAL; 677c29fa5a6Sopenharmony_ci return nullptr; 678c29fa5a6Sopenharmony_ci } 679c29fa5a6Sopenharmony_ci // Searching with specific devtype is not supported, since not used by libinput 680c29fa5a6Sopenharmony_ci CHKPP(devtype); 681c29fa5a6Sopenharmony_ci return device->GetParentWithSubsystem(subsystem); 682c29fa5a6Sopenharmony_ci} 683c29fa5a6Sopenharmony_ci 684c29fa5a6Sopenharmony_ciconst char *udev_device_get_syspath(udev_device *device) 685c29fa5a6Sopenharmony_ci{ 686c29fa5a6Sopenharmony_ci CHKPP(device); 687c29fa5a6Sopenharmony_ci return device->GetSyspath().c_str(); 688c29fa5a6Sopenharmony_ci} 689c29fa5a6Sopenharmony_ci 690c29fa5a6Sopenharmony_ciconst char *udev_device_get_sysname(udev_device *device) 691c29fa5a6Sopenharmony_ci{ 692c29fa5a6Sopenharmony_ci CHKPP(device); 693c29fa5a6Sopenharmony_ci return device->GetSysname().c_str(); 694c29fa5a6Sopenharmony_ci} 695c29fa5a6Sopenharmony_ci 696c29fa5a6Sopenharmony_ciconst char *udev_device_get_devnode(udev_device *device) 697c29fa5a6Sopenharmony_ci{ 698c29fa5a6Sopenharmony_ci CHKPP(device); 699c29fa5a6Sopenharmony_ci return device->GetDevnode().c_str(); 700c29fa5a6Sopenharmony_ci} 701c29fa5a6Sopenharmony_ci 702c29fa5a6Sopenharmony_ciint udev_device_get_is_initialized(udev_device *device) 703c29fa5a6Sopenharmony_ci{ 704c29fa5a6Sopenharmony_ci return (device != nullptr) ? static_cast<int>(device->IsInitialized()) : -1; 705c29fa5a6Sopenharmony_ci} 706c29fa5a6Sopenharmony_ci 707c29fa5a6Sopenharmony_ciconst char *udev_device_get_property_value(udev_device *device, const char *key) 708c29fa5a6Sopenharmony_ci{ 709c29fa5a6Sopenharmony_ci CHKPP(device); 710c29fa5a6Sopenharmony_ci CHKPP(key); 711c29fa5a6Sopenharmony_ci std::string skey{ key }; 712c29fa5a6Sopenharmony_ci if (!device->HasProperty(key)) { 713c29fa5a6Sopenharmony_ci return nullptr; 714c29fa5a6Sopenharmony_ci } 715c29fa5a6Sopenharmony_ci return device->GetProperty(key).c_str(); 716c29fa5a6Sopenharmony_ci} 717