Why bother
apt install linux-image-amd64 is fine. It will be fine for most people
forever. I do not run it on my workstation. The reason is small and concrete:
the audio hardware on modern x86 laptops and motherboards is rapidly enough
moving that the kernel my distribution ships when I install it is regularly
not the kernel that knows how to drive the audio paths I actually have. By
the time the fix reaches a stable release and is backported into the
distribution kernel, six months have passed and I have not had a working
microphone the whole time.
So I build my own. Not a once-a-decade adventure — the everyday kernel I
boot into. Currently linux-image-6.18.34-x64v3-xanmod1-audio, with
matching linux-headers and linux-libc-dev packages installed side by
side. The build flow is the part worth talking about; the audio-stack work
the build flow exists to enable is the more interesting part.
The build flow
The starting point is a cloned XanMod tree — a maintained patch stack atop mainline that gives me lower-latency scheduler defaults and a sane base for desktop workloads. On top of that I lay the audio patches I care about — codec quirks, smart-amp driver fixes, ALSA UCM2 profiles, ACPI subsystem-ID matchings — that have not yet landed upstream or have not yet propagated to a release.
A few choices that aren’t accidental:
- A hand-crafted
EXTRAVERSIONand a distinct release codename. The installed package name encodes the patch stack (xanmod1-audio), anduname -rtells me at a glance what is actually running. Kernel debugging is hard enough without ambiguity about which kernel you are debugging. x64v3ISA targeting. Compile for the actual instruction set on the machine and let the optimizer use it. The portability cost is zero — this kernel only ever runs on this hardware.- Full Debian packaging. Not an out-of-tree blob, not a manually-copied
bzImage. A proper.debwith a realchangelog,control,files,rules, and substvars — produced by the standard build flow, installable and removable throughdpkglike anything else. Thelinux-headersandlinux-libc-devpackages are built and installed alongside the image so anything else on the system that wants to compile against this kernel (out-of-tree Wi-Fi drivers, virtualbox modules, the V4L2 loopback module) finds the headers where it expects them.
I keep multiple trees checked out — 6.8, 6.11, the Rockchip 6.6 vendor tree for SBC work, the XanMod tree for the daily driver — so when something breaks I can bisect across the relevant one without reconstructing the environment from scratch.
What the audio patches actually are
This is the half that justifies the build pipeline. Modern x86 audio is no longer a single chip with a single driver — it is a stack:
- Sound Open Firmware (SOF) is the firmware running on the audio DSP, with its own topology files describing pipelines, mixers, and endpoints.
- ALSA Use Case Manager (UCM2) profiles tell userspace how to route audio for a given hardware configuration (which jack is the headset, what to do when the speakers are routed through a separate amplifier, etc).
- HDA codec quirks match specific machine models to specific pin configurations and verb sequences so the codec actually wakes up correctly.
- I²C smart-amp drivers like
snd_soc_aw88399drive standalone amplifier chips that sit between the DSP and the speakers, with their own firmware and their own calibration. - DMI/ACPI subsystem-ID quirks are the glue: how does the kernel know which machine it is on, and therefore which of the above pieces apply?
A new laptop landing without working audio is, almost always, one or more of these layers missing a quirk or a topology entry for that specific machine’s identifier. The fix is the same shape every time — find the identifier, write the quirk, route it through the right subsystem — and upstreaming it is the actual contribution; running the kernel that includes it is just a daily-driver detail.
The reason I run the kernel I built rather than waiting is that I am the person closing the loop. I write the quirk, build the kernel with the quirk, boot it, confirm audio works, submit the patch upstream, and keep running the local build until the upstream patch lands in a release. Without the build pipeline that whole loop is gated on someone else’s release cadence.
Userspace audio too
The kernel work has a userspace mirror: a locally-built
qpwgraph for visual PipeWire graph
inspection (Qt6 / C++20 / CMake) and a tracked PipeWire configuration the
patches were tuned for. The point is the same: if you are debugging audio
plumbing, you want the graph tool that matches the graph you are debugging,
not whatever version your distribution shipped six months ago.
Closer
The whole flow — kernel patch → personal kernel package → daily driver → upstream patch — is mundane in any given iteration. The compounding effect is that “audio doesn’t work on Linux on my hardware” is a problem I have been causally responsible for solving on my own machine for years, and the same skills make the upstream-contribution side cheap. There is no mystery to the Linux audio stack; there is just a stack of layers each of which rewards someone willing to read its actual source.