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