Skip to content

Build1 publisher3 min readPublished

A dark mute LED traced to one missing line in the kernel's Realtek quirk table

An HP Omen's mute light never lit under Linux because the audio driver had no per-machine fixup to write the codec coefficient that drives it. The merged fix is a single quirk-table entry.

The Engineer · Build desk

Photograph accompanying A dark mute LED traced to one missing line in the kernel's Realtek quirk table
Photo: phoronix.com

What happened

  • On an HP Omen 16-wd0xxx running Linux, pressing mute silenced the audio while the LED that is supposed to signal mute stayed unlit.
  • The same machine lit the same LED correctly under Windows, so the light itself was not dead hardware.
  • evtest showed the mute key emitting an event identical in shape to Caps Lock, and the audio really was muting, which put the fault after input handling.
  • A workaround from Reddit wrote raw hex values directly into codec registers from userspace, and it worked, wrapped in a shell script that a systemd service ran at boot and on each mute change.
  • Maintainer Takashi Iwai applied the resulting patch: one quirk-table entry pointing the Omen at the ALC245 V1 mute-LED fixup.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • cost Moving a fix from userspace into the driver is paid for in build time, because a quirk entry cannot be validated without booting a kernel that already contains it.
  • constraint The quirk table matches one subsystem ID at a time, so the hundred-odd HP entries do nothing for a variant nobody has submitted a line for, however many models share the codec.
  • capability Owners of this model get a working mute LED from a stock kernel, with no boot-time service writing to codec registers as root.
  • decision Anyone currently running the register-poking script has a choice: keep maintaining a systemd unit per machine, or confirm the coefficient and send the subsystem ID upstream once.

Nothing under `/sys/class/leds` corresponded to the mute light [4]. That check decides which fix applies. A class device would mean a driver already owns the light and some trigger is wired wrong. With no class device, the light is driven from the codec, and it only changes state when the audio driver issues a coefficient write for that specific machine.

In `sound/hda`, the per-machine knowledge is a table. `alc269.c` is the actively maintained one, holding `SND_PCI_QUIRK` entries that map a laptop's PCI subsystem ID to the fixup its codec needs; `alc260.c` covers an older generation [7]. HP alone accounts for close to a hundred entries, because every vendor wires the same Realtek part slightly differently [8]. The Omen reports a Realtek ALC245 [6]. No entry matched its subsystem ID, so the driver loaded no fixup and never issued the write.

"It didn't sit right, though. I was reaching into codec registers from userspace on every boot, for something that felt like a solved problem at the driver level," the author wrote [21].

The verification is the part worth copying. Two `hda-verb` commands drive the light: select coefficient `0x0b`, then write `0x7778` for on or `0x7774` for off [9]. Read with no fixup loaded, the coefficient was unchanged across a mute toggle [10]. Written by hand, `0x7778` lit the LED instantly and `0x7774` cleared it [11]. The two values differ in bits 2 and 3 only [22].

Fixup names are not a guide to any of that. `ALC245_FIXUP_HP_MUTE_LED_V2_COEFBIT` went in first, on the assumption that the newer number was the better match, and the LED came up dim and half-toggled [12]. V1 matched the hand test exactly, because the two fixups target different coefficient bits [13].

Then the adoption cost. Testing a fixup means booting a kernel that contains it, and Arch ships no packaged kernel with room for an out-of-tree quirk, so mainline had to be built locally [14]. The first attempt pushed the rebuilt module into the already-running kernel, failed, and every iteration after that was a full build and a reboot [15]. Submission needed a second version too: entries are sorted by PCI device ID, and the first patch put the line roughly where it looked relevant [17]. Per the post, that was a convention rather than a logic bug, which is another way of saying nothing in the build catches it [17].

The merged line is `SND_PCI_QUIRK(0x103c, 0x8ba9, "HP Omen 16-wd0xxx", ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT)` [16]. One subsystem ID, one model. A week later, kernel.org Bugzilla bug #221982 reported the identical symptom on an HP Victus Gaming 15-fa1xxx [19], a different model, so the merged entry does not match it and that machine needs its own line confirmed the same way [23]. The post as published breaks off before saying whether that entry was sent. For anyone else with a dead mute LED, this route applies when the light is absent from `/sys/class/leds` and the codec is one `alc269.c` already handles; a light that does appear as a class device is a different bug.

What to watch

  • Whether a quirk entry for the HP Victus Gaming 15-fa1xxx subsystem ID lands from kernel.org bug #221982.
  • Whether the Omen entry gets picked up for stable backports, or waits for the next mainline release to reach distro kernels.
  • Whether hid_guard, the author's other patch series, clears maintainer review.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories