]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
backlight: fix issue on multiple graphics cards system 24250/head
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 8 Aug 2022 17:02:02 +0000 (02:02 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 17 Aug 2022 05:22:43 +0000 (14:22 +0900)
If a system has multiple graphics cards, then we cannot associate
platform backlight devices to backlight devices under PCI bus.

Previously, in such case, vaidate_device() for a raw backlight device
might erroneously detect a platform device and return false. So, users
could not save/load backlight level.

This makes validate_device() give up to associate platform devices on
non-PCI bus with raw backlight devices. That may cause unwanted
backlight level save or restore by systemd-backlight@.service, but users
can workaround that by masking specific instances of the service.

Closes #24223.

src/backlight/backlight.c

index b01b94b2b6cd887f583be927043b1df16fac4d65..b6474d31a72378d85a989ee39c7bc3f47e09f89c 100644 (file)
@@ -21,6 +21,8 @@
 #include "terminal-util.h"
 #include "util.h"
 
+#define PCI_CLASS_GRAPHICS_CARD 0x30000
+
 static int help(void) {
         _cleanup_free_ char *link = NULL;
         int r;
@@ -44,6 +46,47 @@ static int help(void) {
         return 0;
 }
 
+static int has_multiple_graphics_cards(void) {
+        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+        sd_device *dev;
+        bool found = false;
+        int r;
+
+        r = sd_device_enumerator_new(&e);
+        if (r < 0)
+                return r;
+
+        r = sd_device_enumerator_add_match_subsystem(e, "pci", /* match = */ true);
+        if (r < 0)
+                return r;
+
+        /* class is an unsigned number, let's validate the value later. */
+        r = sd_device_enumerator_add_match_sysattr(e, "class", NULL, /* match = */ true);
+        if (r < 0)
+                return r;
+
+        FOREACH_DEVICE(e, dev) {
+                const char *s;
+                unsigned long c;
+
+                if (sd_device_get_sysattr_value(dev, "class", &s) < 0)
+                        continue;
+
+                if (safe_atolu(s, &c) < 0)
+                        continue;
+
+                if (c != PCI_CLASS_GRAPHICS_CARD)
+                        continue;
+
+                if (found)
+                        return true; /* This is the second device. */
+
+                found = true; /* Found the first device. */
+        }
+
+        return false;
+}
+
 static int find_pci_or_platform_parent(sd_device *device, sd_device **ret) {
         const char *subsystem, *sysname, *value;
         sd_device *parent;
@@ -86,7 +129,7 @@ static int find_pci_or_platform_parent(sd_device *device, sd_device **ret) {
                                                  value, subsystem, sysname);
 
                 /* Graphics card */
-                if (class == 0x30000) {
+                if (class == PCI_CLASS_GRAPHICS_CARD) {
                         *ret = parent;
                         return 0;
                 }
@@ -200,6 +243,23 @@ static int validate_device(sd_device *device) {
         if (r < 0)
                 return log_debug_errno(r, "Failed to add sysattr match: %m");
 
+        if (streq(subsystem, "pci")) {
+                r = has_multiple_graphics_cards();
+                if (r < 0)
+                        return log_debug_errno(r, "Failed to check if the system has multiple graphics cards: %m");
+                if (r > 0) {
+                        /* If the system has multiple graphics cards, then we cannot associate platform
+                         * devices on non-PCI bus (especially WMI bus) with PCI devices. Let's ignore all
+                         * backlight devices that do not have the same parent PCI device. */
+                        log_debug("Found multiple graphics cards on PCI bus. "
+                                  "Skipping to associate platform backlight devices on non-PCI bus.");
+
+                        r = sd_device_enumerator_add_match_parent(enumerate, parent);
+                        if (r < 0)
+                                return log_debug_errno(r, "Failed to add parent match: %m");
+                }
+        }
+
         FOREACH_DEVICE(enumerate, other) {
                 const char *other_subsystem;
                 sd_device *other_parent;