Ben Leskey | Blog

Fixing HP Victus 15 internal microphone drivers by compiling patched auto-updating kernel with openSUSE Tumbleweed Open Build Service

2024-12-25 #debugging #software

I've recently moved to a new laptop. OpenSUSE tumbleweed is still my OS of choice, and my recent experience cemented its position as my favorite Linux distro. My new device is an HP Victus 15, specs below:

Operating System: openSUSE Tumbleweed 20241222
KDE Plasma Version: 6.2.4
KDE Frameworks Version: 6.9.0
Qt Version: 6.8.1
Kernel Version: 6.12.6-5.gfb072de-default (64-bit)
Graphics Platform: X11
Processors: 12 × AMD Ryzen 5 7535HS with Radeon Graphics
Memory: 14.8 GiB of RAM
Graphics Processor: AMD Radeon 660M
Manufacturer: HP
Product Name: Victus by HP Gaming Laptop 15-fb2xxx

The only hardware issue encountered on this device was that the internal microphone was not recognized. For example, using arecord -l to list my sound devices, I only saw the unplugged microphone device, even though my devices were shown in inxi -A:

$ arecord -l
**** List of CAPTURE Hardware Devices ****
card 2: Generic_1 [HD-Audio Generic], device 0: ALC245 Analog [ALC245 Analog]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
$ inxi -A
Audio:
  Device-1: Advanced Micro Devices [AMD/ATI] Navi 21/23 HDMI/DP Audio
    driver: snd_hda_intel
  Device-2: Advanced Micro Devices [AMD/ATI] Rembrandt Radeon High
    Definition Audio driver: snd_hda_intel
  Device-3: Advanced Micro Devices [AMD] ACP/ACP3X/ACP6x Audio Coprocessor
    driver: snd_pci_acp6x
  Device-4: Advanced Micro Devices [AMD] Family 17h/19h/1ah HD Audio
    driver: snd_hda_intel
  API: ALSA v: k6.12.6-5.gfb072de-default status: kernel-api
  Server-1: PipeWire v: 1.2.7 status: active
After much research I found the fix. I needed to add a linux kernel quirk patch for my specific model in the ACP6X sound driver for the internal microphone. The patch to the kernel itself is extremely simple, just adding my hardware to the quirk list so that even though Linux does not autodetect the correct driver, it will load it anyway:

diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c
index ecf57a6..c95198c 100644
--- a/sound/soc/amd/yc/acp6x-mach.c
+++ b/sound/soc/amd/yc/acp6x-mach.c
@@ -458,6 +458,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
 			DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16z-n000"),
 		}
 	},
+	{
+		.driver_data = &acp6x_card,
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Victus by HP Gaming Laptop 15-fb2xxx"),
+		}
+	},
 	{
 		.driver_data = &acp6x_card,
 		.matches = {

So far, so good. But here's where OpenSUSE shines: using the Open Build Service, I was able to create a new set of kernel packages with my patch that automatically keep up with the latest tumbleweed kernel. This reddit comment was very helpful, reproduced below:

  1. Go to https://build.opensuse.org/package/show/openSUSE:Factory/kernel-source
  2. sign in
  3. click branch
  4. optional step - use the command line tool osc to download, edit and test the build locally.
  5. overwrite the config.tar.bz2 with your .config tar bzipped
  6. Make package links to kernel-source and call them kernel-default, kernel-devel and kernel-syms
  7. Draw the rest of the owl
  8. Wait for it to build successfully
  9. Add the repo to your TW installation (links are on the webpage) and switch the kernel packages over

I more or less followed these steps, with some details below:

First, I installed the kernel-source package so I could test and install my fix locally, using the following:


$ cd linux-build-directory

$ make -C /usr/src/linux O=$PWD oldconfig # Create a kernel config based on my running kernel config
[...]

# In the .config file, I updated CONFIG_LOCALVERSION to differentiate my compiled kernel,
# and removed the reference to the OpenSUSE keys in CONFIG_MODULE_SIG_KEYS

# I also added a modprobe configuration file:
$ cat /etc/modprobe.d/10-unsupported-modules.conf
allow_unsupported_modules 1

$ make -j12 # It builds.

$ sudo make modules_install -j12 # Adds the kernel modules to /usr/lib/modules

$ sudo make install -j12 # Installs the kernel to /boot and updates the bootloader

At this point I created the patch diff of my changes using the original file and my new file:


$ git diff /tmp/old-acp6x-mach.c ./sound/soc/amd/yc/acp6x-mach.c > /tmp/my-new-patch.patch

After this, I rebooted into my custom kernel to verify the fix. To remove the custom compiled kernel from the bootloader list, I just removed the files and updated the bootloader:


$ cd /boot
$ mkdir /home/user/old-linux
$ find | grep my-custom-kernel | sudo xargs -O{} -n1 mv {} /home/user/old-linux # Replace my-custom-kernel with what you put in CONFIG_LOCALVERSION
$ sudo update-bootloader # Get the removed custom kernel off the bootloader menu

I then:

This OpenSUSE infrastructure is incredibly useful, and I am very pleased with my choice of distro and the (relative!) ease of fixing this internal microphone issue without sacrificing update flow. Next step, getting this patch into the upstream Linux kernel!