Only "Dummy Output" and HDMI, no speakers, no microphone, on a Huawei MateBook with an AMD Ryzen CPU? Your laptop model is probably missing from two hard-coded allow-lists inside the Linux kernel. This repository registers it, without recompiling the kernel.
Verified on HUAWEI NBM-WXX9 (MateBook D, product version M1010, board NBM-WXX9-PCB-B2), AMD Lucienne/Renoir, Arch Linux, kernel 7.1.5. The scripts are model-agnostic and read your DMI data at runtime, so they work for any Huawei/AMD laptop that hits the same wall.
-
pavucontrol/ GNOME / KDE show only Dummy Output; no internal speakers, no internal or headset microphone. -
HDMI audio works, and that is the only card present:
$ cat /proc/asound/cards 0 [Generic ]: HDA-Intel - HD-Audio Generic HD-Audio Generic at 0xd03c0000 irq 78 -
The AMD Audio Co-Processor has no driver bound:
$ lspci -k | grep -A3 'Audio Coprocessor' 03:00.5 Multimedia controller: AMD Audio Coprocessor (rev 01) Kernel modules: snd_pci_acp3x, snd_rn_pci_acp3x, snd_acp_pci, snd_sof_amd_renoir, ... # note: no "Kernel driver in use" line -
The codec is there in ACPI (
ESSX8336:00) and its i2c driveres8316is bound — the codec is not the problem. -
If you get as far as loading the machine driver, the kernel says:
acp_mach acp3x-es83xx: this system has a ES83xx codec defined in ACPI, but the driver doesn't have this system registered in DMI table acp_mach acp3x-es83xx: Cannot probe card (acp3x-es83xx): -19
Search terms this page answers: Huawei MateBook no sound Linux, MateBook D14/D15/D16 AMD dummy output, ES8336 ES8316 no sound, AMD ACP audio not working, NBM-WXX9 sound, acp3x-es83xx Cannot probe card -19, doesn't have this system registered in DMI table, snd_acp_pci not bound, Ryzen laptop only HDMI audio.
Audio on these laptops does not go through the usual HD-Audio codec. It goes through the AMD ACP
(Audio Co-Processor, PCI function 03:00.5) with an Everest ES8336 codec wired over I2S. The kernel only
drives that path on machines it explicitly recognises, and it checks two separate DMI allow-lists:
| Module | Decides |
|---|---|
snd-acp-config.ko |
whether any driver claims the ACP PCI function at all |
snd-acp-legacy-mach.ko |
whether the sound card is actually registered |
Both tables list a handful of Huawei models (KLVL-WXX9, KLVL-WXXW, BOM-WXX9, HVY-WXX9, …).
If yours is absent, the first table makes every candidate driver decline the device silently — no error,
no card, nothing in the log. That silence is what makes this so hard to diagnose.
This is an upstream gap, not a distribution bug: the same tables ship in every distribution's kernel, so switching from Arch to Ubuntu/Fedora/Mint changes nothing. Reported upstream and still open — see codepayne/linux-sound-huawei#33 (March 2024).
Distribution kernel modules are signed. Editing the payload invalidates that signature, and the kernel rejects a module with a broken signature outright:
modprobe: ERROR: could not insert 'snd_acp_config': Key was rejected by service
This happens even with CONFIG_MODULE_SIG_FORCE disabled, Secure Boot off and lockdown none — those settings
only relax the rules for modules with no signature, not for one that fails verification. So the patcher
removes the appended signature block instead of trying to keep it. The module then loads as unsigned and the
kernel sets a taint flag (8192), which is informational only.
Requirements: zstd, python3, depmod (kmod). Root. Arch-based distros get the kernel-update hook automatically.
git clone https://github.com/bindinwin-eng/huawei-matebook-amd-linux-audio-fix.git
cd huawei-matebook-amd-linux-audio-fix
sudo ./install.sh
sudo rebootWant to look before you leap:
./diagnose.sh # read-only, confirms you have this exact problem
sudo ./install.sh --dry-run # shows what would change, writes nothinginstall.sh does three things:
- disables any
/etc/modprobe.d/*.confthat blacklists the ACP drivers (renamed to*.disabled-<date>, never deleted) and rebuilds the initramfs, because such a blacklist is baked in there too; - patches the DMI tables for every installed kernel, keeping each original as
<module>.orig; - installs a pacman hook so the patch is reapplied automatically after every kernel update.
$ cat /proc/asound/cards
0 [Generic ]: HDA-Intel - HD-Audio Generic
1 [acp3xes83xx ]: acp3x-es83xx - acp3x-es83xx
HUAWEI-NBM_WXX9-M1010-NBM_WXX9_PCB_B2
$ journalctl -k -b | grep acp_mach
acp_mach acp3x-es83xx: matched DMI table with this system, trying to register sound card
acp_mach acp3x-es83xx: successfully probed the sound card
es8316 i2c-ESSX8336:00: speaker gpio 0 active high, headphone gpio 1 active high
es8316 i2c-ESSX8336:00: Headset Mic is MIC2Speakers, headphone jack with detection, and the headset microphone all come up.
sudo ./uninstall.sh && sudo rebootRestores the original signed modules from the .orig copies and removes the hook.
Both tables are arrays of struct dmi_system_id. Each entry stores its match strings inline as
struct dmi_strmatch { u8 slot; char substr[79]; }, so a model name sits at a fixed 80-byte stride from the
vendor string and the product version sits 80 bytes after the name:
[ HUAWEI ][ KLVL-WXX9 ][ M1010 ] ...
+0 +80 +160
The patcher therefore does not need to recompile anything. It:
- reads
sys_vendor,product_nameandproduct_versionfrom/sys/class/dmi/id; - finds donor entries — entries whose vendor and product version already equal yours, and whose model name is at least as long as yours (the replacement must fit in place, since moving bytes would break every offset);
- overwrites one donor model name with yours, keeping the file size byte-identical;
- strips the appended module signature;
- runs
depmod.
Overwriting is safe here because every entry in both tables carries NULL pointers for callback, ident and
driver_data — verified by parsing the ELF relocations, which show no relocation anywhere inside either table.
The tables are pure allow-lists: the actual per-machine configuration (speaker/headphone GPIOs, mic routing) comes
from ACPI at probe time. So donors are interchangeable, and the only cost is that the donated model is no longer
listed — irrelevant unless you own two different MateBooks.
The original is kept as <module>.orig and is used as the source on every run, which makes repeated runs and
kernel-update hooks idempotent.
The scripts auto-detect your machine, so usually there is nothing to adapt. If you want control:
sudo acp-audio-dmi-fix --dry-run # what would happen
sudo acp-audio-dmi-fix --donor HVY-WXX9 # pick which entry gets overwritten
sudo acp-audio-dmi-fix --model MY-MODEL # inject a name other than DMI product_name
sudo acp-audio-dmi-fix --kernel 6.12.4-arch1-1If your product version differs from every listed entry (M1010, M1020, M1040), no donor will be found and
the script refuses to guess — that case needs a real kernel patch, because both the name and the version would have
to change and there may not be room.
- The kernel is marked tainted (
8192, "unsigned module"). Informational; it can matter if you report unrelated bugs to kernel maintainers. - Secure Boot must be off, otherwise an unsigned module cannot load at all. (If you run Secure Boot with your own keys, re-sign the patched modules instead of relying on the taint path.)
- The patch is per kernel build. The pacman hook handles Arch; on other distros wire
/usr/local/bin/acp-audio-dmi-fixinto your kernel post-install path. - The donated model loses its entry.
- This is a workaround. The clean fix is a three-line DMI entry upstream — see below.
Add your machine to acp_quirk_table in sound/soc/amd/acp-config.c and to acp3x_es83xx_dmi_table in
sound/soc/amd/acp/acp-legacy-mach.c, then send it to ALSA/kernel maintainers. Once that lands and reaches your
distribution, uninstall this and enjoy stock, signed modules. Patches welcome here too — if you get your model
merged upstream, open an issue so it can be listed as no longer needing this.
Roughly 90% of this repository was written by Claude (Anthropic's Claude Code, Opus 5) during a single interactive debugging session on the affected laptop: the diagnosis, the binary analysis of the kernel modules and their DMI tables, the ELF relocation check that proved donor entries are interchangeable, the patcher, the installer and this README.
The human half of the session supplied the hardware, ran every privileged command, and verified the result on real speakers. Both halves were needed — but credit where it is due.
MIT — see LICENSE.