]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
udev-util: ignore USB-C ports in power source mode when detecting system is running... 22006/head
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 5 Jan 2022 00:10:35 +0000 (09:10 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 6 Jan 2022 09:28:56 +0000 (18:28 +0900)
Fixes #21988.

src/shared/udev-util.c

index 800493afe9e614bde6f2d481632bc42120074f73..56c28773ceda270bc5f82409536619fea8385263 100644 (file)
@@ -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");