diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2022-01-05 01:10:35 +0100 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2022-01-06 10:28:56 +0100 |
commit | 795e86b4f1e8a1fd440f8c817621779c6aedbdb5 (patch) | |
tree | e9659789a639fb21dabc60bf7a02fdbf2430f637 /src/shared/udev-util.c | |
parent | udev-util: re-implement on_ac_power() with sd-device (diff) | |
download | systemd-795e86b4f1e8a1fd440f8c817621779c6aedbdb5.tar.xz systemd-795e86b4f1e8a1fd440f8c817621779c6aedbdb5.zip |
udev-util: ignore USB-C ports in power source mode when detecting system is running on AC power
Fixes #21988.
Diffstat (limited to 'src/shared/udev-util.c')
-rw-r--r-- | src/shared/udev-util.c | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/src/shared/udev-util.c b/src/shared/udev-util.c index 800493afe9..56c28773ce 100644 --- a/src/shared/udev-util.c +++ b/src/shared/udev-util.c @@ -580,6 +580,66 @@ int udev_queue_init(void) { return TAKE_FD(fd); } +static int device_is_power_sink(sd_device *device) { + _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; + bool found_source = false, found_sink = false; + sd_device *parent, *d; + int r; + + assert(device); + + /* USB-C power supply device has two power roles: source or sink. See, + * https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-typec */ + + r = sd_device_enumerator_new(&e); + if (r < 0) + return r; + + r = sd_device_enumerator_allow_uninitialized(e); + if (r < 0) + return r; + + r = sd_device_enumerator_add_match_subsystem(e, "typec", true); + if (r < 0) + return r; + + r = sd_device_get_parent(device, &parent); + if (r < 0) + return r; + + r = sd_device_enumerator_add_match_parent(e, parent); + if (r < 0) + return r; + + FOREACH_DEVICE(e, d) { + const char *val; + + r = sd_device_get_sysattr_value(d, "power_role", &val); + if (r < 0) { + if (r != -ENOENT) + log_device_debug_errno(d, r, "Failed to read 'power_role' sysfs attribute, ignoring: %m"); + continue; + } + + if (strstr(val, "[source]")) { + found_source = true; + log_device_debug(d, "The USB type-C port is in power source mode."); + } else if (strstr(val, "[sink]")) { + found_sink = true; + log_device_debug(d, "The USB type-C port is in power sink mode."); + } + } + + if (found_sink) + log_device_debug(device, "The USB type-C device has at least one port in power sink mode."); + else if (!found_source) + log_device_debug(device, "The USB type-C device has no port in power source mode, assuming the device is in power sink mode."); + else + log_device_debug(device, "All USB type-C ports are in power source mode."); + + return found_sink || !found_source; +} + int on_ac_power(void) { _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; bool found_offline = false, found_online = false; @@ -617,6 +677,18 @@ int on_ac_power(void) { continue; } + /* Ignore USB-C power supply in source mode. See issue #21988. */ + if (streq(val, "USB")) { + r = device_is_power_sink(d); + if (r <= 0) { + if (r < 0) + log_device_debug_errno(d, r, "Failed to determine the current power role, ignoring: %m"); + else + log_device_debug(d, "USB power supply is in source mode, ignoring."); + continue; + } + } + r = sd_device_get_sysattr_value(d, "online", &val); if (r < 0) { log_device_debug_errno(d, r, "Failed to read 'online' sysfs attribute, ignoring: %m"); |