backlight: fix issue on multiple graphics cards system

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.
This commit is contained in:
Yu Watanabe 2022-08-09 02:02:02 +09:00
parent f8ff4b6076
commit e0504dd011

View 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;