Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libs/libudev-zero/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk

PKG_NAME:=libudev-zero
PKG_VERSION:=1.0.5
PKG_RELEASE:=2
PKG_RELEASE:=3

PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/illiliti/libudev-zero/tar.gz/$(PKG_VERSION)?
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
From 584578c0deac728780108a6b80ecda4e6e608cca Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Wed, 9 Sep 2026 02:09:58 +0100
Subject: [PATCH] udev_device: mark sound cards as initialised

PipeWire's ALSA udev plugin skips every sound card whose udev device
lacks the SOUND_INITIALIZED property, which udev's 78-sound-card rule
sets once alsactl has restored the card. Without udev nothing sets it,
so PipeWire never sees a card and offers only a dummy output. Add the
property to sound card devices the way ID_INPUT is synthesised for
input devices.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
udev_device.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)

--- a/udev_device.c
+++ b/udev_device.c
@@ -540,6 +540,27 @@ static void set_properties_from_props(st
udev_list_entry_add(&udev_device->properties, "ID_PATH", id, 0);
}

+static void set_properties_from_sound(struct udev_device *udev_device)
+{
+ const char *devpath, *subsystem, *name;
+
+ subsystem = udev_device_get_subsystem(udev_device);
+ devpath = udev_device_get_devpath(udev_device);
+
+ if (!subsystem || !devpath || strcmp(subsystem, "sound") != 0) {
+ return;
+ }
+
+ name = strrchr(devpath, '/');
+
+ if (!name || strncmp(name, "/card", 5) != 0) {
+ return;
+ }
+
+ /* udev sets this once alsactl has run; nothing else can here */
+ udev_list_entry_add(&udev_device->properties, "SOUND_INITIALIZED", "1", 0);
+}
+
struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath)
{
char *subsystem, *driver, *sysname;
@@ -593,6 +614,7 @@ struct udev_device *udev_device_new_from

set_properties_from_evdev(udev_device);
set_properties_from_props(udev_device);
+ set_properties_from_sound(udev_device);

free(driver);
free(subsystem);
@@ -712,6 +734,7 @@ struct udev_device *udev_device_new_from

set_properties_from_props(udev_device);
set_properties_from_evdev(udev_device);
+ set_properties_from_sound(udev_device);
return udev_device;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
From a15d506dbefb531366ad605c44686043de30fb3e Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Wed, 9 Sep 2026 02:14:14 +0100
Subject: [PATCH] udev_enumerate: scan the classes of matched subsystems

/sys/dev lists only devices that own a device node, so an enumeration
never returns class members without one, such as the sound card
objects PipeWire's ALSA plugin looks for: it sees the control and PCM
nodes but never a card. For each subsystem the caller matched, also
scan /sys/class/<subsystem>, skipping syspaths already listed.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
udev_enumerate.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)

--- a/udev_enumerate.c
+++ b/udev_enumerate.c
@@ -241,7 +241,9 @@ static void add_device(struct udev_enume
return;
}

- udev_list_entry_add(&udev_enumerate->devices, udev_device_get_syspath(udev_device), NULL, 0);
+ if (!udev_list_entry_get_by_name(&udev_enumerate->devices, udev_device_get_syspath(udev_device))) {
+ udev_list_entry_add(&udev_enumerate->devices, udev_device_get_syspath(udev_device), NULL, 0);
+ }

udev_device_unref(udev_device);
}
@@ -279,6 +281,8 @@ static int scan_devices(struct udev_enum
int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate)
{
const char *path[] = { "/sys/dev/block", "/sys/dev/char", NULL };
+ struct udev_list_entry *list_entry;
+ char class_path[PATH_MAX];
int i;

if (!udev_enumerate) {
@@ -291,6 +295,15 @@ int udev_enumerate_scan_devices(struct u
}
}

+ /* /sys/dev only lists devices with a node; a matched class may hold more */
+ list_entry = udev_list_entry_get_next(&udev_enumerate->subsystem_match);
+
+ while (list_entry) {
+ snprintf(class_path, sizeof(class_path), "/sys/class/%s", udev_list_entry_get_name(list_entry));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Subsystem matches are fnmatch() patterns (filter_subsystem() at udev_enumerate.c:105-111), so a glob match such as sound* builds a literal /sys/class/sound* path, scandir() fails silently, and node-less class members are still missed. Optional: scan /sys/class and fnmatch() each entry against the pattern instead. PipeWire's literal sound match is unaffected, so this does not block the merge.


Generated by Claude Code

+ scan_devices(udev_enumerate, class_path);
+ list_entry = udev_list_entry_get_next(list_entry);
+ }
+
return 0;
}

Loading