Audio
├─ Devices: 48. HDA Intel [alsa]
├─ Sinks: * 52. HDA Intel Analog Stereo [vol: 0.40]
├─ Sources: * 53. HDA Intel Analog Stereo [vol: 1.00]
Y gvc con perfiles reales (`output:analog-stereo+input:analog-stereo`). Se fue el auto_null.
LA CAUSA: SPA pide el device `card` (alsa-udev.c:178-183), que no tiene major:minor, y
libudev-zero recorría SÓLO /sys/dev/{block,char} — sólo devices CON nodo. El device que
SPA necesita nunca entraba en la enumeración: no faltaba una propiedad, faltaba la mitad
del espacio de búsqueda.
**Y LA PRIMERA VERSIÓN DEL PARCHE ARREGLÓ EL AUDIO Y ROMPIÓ EL VÍDEO.** Recorría
/sys/class entero, y /sys/class/drm no trae sólo tarjetas: trae los CONECTORES
(card0-Virtual-1) y un fichero `version`, ninguno con nodo. Mutter los tomaba como
candidatos ⇒ `No available CRTC for monitor` + `Page flip failed: drmModeAtomicCommit:
Invalid argument` en bucle. Pantalla negra con el compositor vivo: el mismo síntoma de
antes por una causa nueva. El udev real también los enumera, pero les adjunta las
propiedades por las que mutter los descarta, y ésas libudev-zero no las sintetiza.
La lección, que vale para cualquier reimplementación parcial de una API: **ensanchar la
enumeración expone los huecos de PROPIEDADES a más consumidores. Los dos lados del
contrato tienen que crecer juntos.** El parche final lleva una LISTA ACOTADA de
subsistemas (`sound` hoy); agregar otro es una línea *y* una prueba de que el consumidor
lo necesita y no se rompe.
POR QUÉ NO eudev — y corrijo mi propia sugerencia de antes, que era la peor opción: el
repo ya lo había probado en otro frente y ROMPIÓ EL INPUT. Su libudev.so.1 pisa el de
libudev-zero y, sin udevd, no expone ID_INPUT ⇒ libinput ignora todos los dispositivos en
silencio. Verificación A/B en QEMU de aquel episodio: eudev = 0 «New device»,
libudev-zero = 5. eudev sin udevd es PEOR, y correr udevd contradice la arquitectura
(arje-zero es PID1). El arreglo va donde está el hueco.
Radio pagado: 51 sellados a deuda, 9 en el cierre GNOME (reconstruidos: libinput,
libgudev, colord, mutter, gnome-shell, libgdm, upower, pipewire, wireplumber). El resto
—base, cli, KDE— queda para el latido.
Captura actualizada: escritorio pintando (628 colores) Y audio, cero page-flip fallidos.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
97 lines
5.1 KiB
Diff
97 lines
5.1 KiB
Diff
libudev-zero: enumerar devices de CLASE para una lista ACOTADA de subsistemas.
|
|
|
|
EL HUECO, medido en las fuentes de los dos lados. `udev_enumerate_scan_devices` recorre
|
|
**exclusivamente** `/sys/dev/block` y `/sys/dev/char` (udev_enumerate.c:281), o sea sólo devices que
|
|
tienen `major:minor` y por tanto nodo en /dev. El udev real recorre `/sys/class` entero. La diferencia
|
|
es invisible para casi todos los consumidores y letal para los que piden un device de CLASE.
|
|
|
|
CÓMO SE DESTAPÓ: el audio. `spa/plugins/alsa/alsa-udev.c:178-183` de PipeWire pide el device **card**
|
|
—`/sys/devices/.../sound/card0`—, que es de clase: sin major:minor, sin nodo. Con ALSA encendido en el
|
|
kernel, `/dev/snd/controlC0` presente y `/sys/class/sound` listando `card0`, `wpctl status` daba
|
|
`Devices:` vacío **porque card0 nunca entraba en la enumeración**. No era una propiedad que faltara:
|
|
faltaba la mitad del espacio de búsqueda.
|
|
|
|
⚠ POR QUÉ UNA LISTA Y NO `/sys/class` ENTERO — se probó global y ROMPIÓ EL VÍDEO
|
|
La primera versión de este parche recorría todo `/sys/class`. El audio pasó a funcionar
|
|
(`48. HDA Intel [alsa]`, sink y source reales en vez de `auto_null`) **y la pantalla se puso negra**:
|
|
|
|
libmutter-WARNING: Failed to use linear monitor configuration:
|
|
No available CRTC for monitor 'RHT QEMU Monitor' not found
|
|
libmutter-WARNING: Page flip failed: drmModeAtomicCommit: Invalid argument (en bucle)
|
|
|
|
`/sys/class/drm` no contiene sólo las tarjetas: contiene los CONECTORES (`card0-Virtual-1`,
|
|
`card1-eDP-1`…) y un fichero `version`, ninguno con nodo. Al aparecer en la enumeración, mutter los
|
|
toma como candidatos y no encuentra CRTC. **El udev real también los enumera** — pero además les
|
|
adjunta las propiedades por las que mutter los descarta, y ésas libudev-zero no las sintetiza (su
|
|
tabla es fija y está orientada a input: `ID_INPUT*`, `EV`, `KEY`, `ABS`, `REL`).
|
|
|
|
La lección, que vale para cualquier reimplementación parcial de una API: **ensanchar la enumeración
|
|
expone los huecos de PROPIEDADES a más consumidores.** Los dos lados del contrato tienen que crecer
|
|
juntos.
|
|
|
|
Así que se agrega subsistema por subsistema, con un caso de uso medido detrás de cada uno. Hoy:
|
|
`sound`. Agregar otro es una línea en `class_subsystems[]` **y una prueba de que el consumidor lo
|
|
necesita y no se rompe**.
|
|
|
|
POR QUÉ ESTO Y NO eudev, y acá el repo ya tenía la respuesta escrita: empaquetar eudev se probó en otro
|
|
frente y **rompió el input** — su `libudev.so.1` pisa el de libudev-zero y, SIN udevd corriendo, eudev
|
|
no expone `ID_INPUT`, así que libinput ignora TODOS los dispositivos EN SILENCIO (`udev_assign_seat`
|
|
devuelve OK con 0 devices). Se resolvió restaurando libudev-zero, con verificación A/B en QEMU: eudev =
|
|
0 «New device», libudev-zero = 5. Ver [[mirada-usb-nvidia]]. eudev sin udevd es PEOR, y correr udevd
|
|
contradice la arquitectura (arje-zero es PID1, sin udevd en el camino).
|
|
|
|
⚠ COSTO: `yupana radio libudev-zero` = **51 artefactos sellados cayendo a deuda** en las cinco
|
|
imágenes (9 en el cierre GNOME). Una variante NO era opción: dos `libudev.so.1` en el mismo rootfs es
|
|
exactamente el choque del episodio de eudev.
|
|
|
|
diff -Naur a/udev_enumerate.c b/udev_enumerate.c
|
|
--- a/udev_enumerate.c
|
|
+++ b/udev_enumerate.c
|
|
@@ -276,6 +276,37 @@
|
|
return 1;
|
|
}
|
|
|
|
+/* Enumera devices de CLASE (los que no tienen major:minor y por tanto no aparecen bajo
|
|
+ * /sys/dev/{block,char}) para una LISTA ACOTADA de subsistemas.
|
|
+ *
|
|
+ * Por que una lista y no /sys/class entero: se probo global y ROMPIO EL VIDEO. /sys/class/drm no
|
|
+ * contiene solo las tarjetas: contiene los CONECTORES (card0-Virtual-1, card1-eDP-1...) y un fichero
|
|
+ * `version`, ninguno con nodo. Al aparecer en la enumeracion, mutter los trata como candidatos y
|
|
+ * termina en `No available CRTC for monitor` + `Page flip failed: drmModeAtomicCommit: Invalid
|
|
+ * argument` en bucle: pantalla negra con el compositor vivo. El udev real tambien los enumera, pero
|
|
+ * ademas les adjunta las propiedades por las que mutter los descarta, y esas propiedades libudev-zero
|
|
+ * no las sintetiza. O sea: ensanchar la enumeracion expone los huecos de PROPIEDADES a mas
|
|
+ * consumidores.
|
|
+ *
|
|
+ * Asi que se agrega subsistema por subsistema, con un caso de uso medido detras de cada uno:
|
|
+ * sound -> PipeWire pide el device `card` de la tarjeta (alsa-udev.c:178-183), que no tiene nodo.
|
|
+ * Sin esto `wpctl status` da `Devices:` vacio con ALSA funcionando y /dev/snd poblado.
|
|
+ */
|
|
+static const char *const class_subsystems[] = { "sound", NULL };
|
|
+
|
|
+static int scan_class(struct udev_enumerate *udev_enumerate)
|
|
+{
|
|
+ char subsystem_path[PATH_MAX];
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; class_subsystems[i]; i++) {
|
|
+ snprintf(subsystem_path, sizeof(subsystem_path), "/sys/class/%s", class_subsystems[i]);
|
|
+ scan_devices(udev_enumerate, subsystem_path);
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate)
|
|
{
|
|
const char *path[] = { "/sys/dev/block", "/sys/dev/char", NULL };
|
|
@@ -291,6 +322,8 @@
|
|
}
|
|
}
|
|
|
|
+ scan_class(udev_enumerate);
|
|
+
|
|
return 0;
|
|
}
|
|
|