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