summaryrefslogtreecommitdiffstats
path: root/src/shared/udev-util.c
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2022-01-05 01:10:35 +0100
committerYu Watanabe <watanabe.yu+github@gmail.com>2022-01-06 10:28:56 +0100
commit795e86b4f1e8a1fd440f8c817621779c6aedbdb5 (patch)
treee9659789a639fb21dabc60bf7a02fdbf2430f637 /src/shared/udev-util.c
parentudev-util: re-implement on_ac_power() with sd-device (diff)
downloadsystemd-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.c72
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");