I got a new laptop last week for work and needed to get it ready. Now new laptops usually mean new hardware and that can spell problems if you are installing linux. This is because the latest hardware may be used and linux usually needs some time to catch up with the latest hardware. This started out with the graphical installation not working. Luckily though, rocky linux 9 also supports a VNC install. So this issue was solved by connecting the laptop to wired ethernet and using VNC from another laptop to do the installation. This all went without problems. Next up was the NVIDIA driver for which I am using the RPM packages from the NVIDIA CUDA repository. These usually work fine, however, this time there was a mismatch where the driver was installed in the wrong directory; easily fixed though by fooling the NVIDIA RPMs by creating a symbolic link in /lib/modules: 5.14.0-162.12.1.el9_1.x86_64 -> 5.14.0-162.12.1.el9_1.0.2.x86_64/.
Finally, there was the sanity check to verify all devices such as webcam, microphone, speakers etc.. This is where all the problems started.
There was no way, it seemed that this laptop was ever going to produce sound, so I googled and googled and slowly got to know more about the problem and how to approach it. All in all it cost me almost 3 full days of googling and trying out stuff before I got everything(!) to work. This post describes the highlights of what I did.
First of all, it is important to understand that there is a new architecture for sound in linux, the Sound Open Firmware that replaces the legacy high defintion audio. There also appears to be a standard troubleshooting approach that was not clear to me until the very end.
Step 1: switch to the legacy HD audio driver
Step 1 of the approach is to switch to the legacy high definition audio using the following setting in a file in /etc/modprobe.d:
options snd-intel-dspcfg dsp_driver=1
After doing this, it is guaranteed that your digital microphone will no longer work, but that is expected so don’t waste time on checking this (as I did).
Step 2: provide firmware overrides by comparing with windows
After step 1 I still did not have any sound. However, using the legacy driver it is possible to patch firmware.
The procedure for finding the required settings is listed here. The procedure involves taking a dump of some parameters of the realtek hardware using a proprietary program from Realtek, and then taking a similar dump of the same parameters on linux using standard tooling (cat). Next is to compare the settings of windows with those on linux and simply provide firmware overrides for every setting where windows does something different from linux. This gave me the firmware file alc294-sound-patch.fw in the /lib/firmware directory:
[codec] 0x10ec0294 0x104312a3 0 [pincfg] 0x19 0x03A11050 0x1a 0x03A11C30 0x21 0x03211420 [verb] 0x20 0x500 0x62 0x20 0x400 0xa007 0x20 0x500 0x10 0x20 0x400 0x8420 0x20 0x500 0x0f 0x20 0x400 0x7774
The codec parameters follow directly from the vendor id, subsystem id, and card number. The pincfg parameters can also be done by comparing the windows and linux dumps. For the verb parameters I compared windows with linux again, but this was unsuccessful. Instead, I found a similar firmware patch file on the internet that agreed perfectly on the vendor id and on the pincfg configuration and that one appeared to work.
This file then needs to be configured in the same file in the /etc/modprobe.d directory by adding the following:
options snd-hda-intel patch=alc294-sound-patch.fw
(actually it can be any file, but keeping it in the same file makes it easy).
An alternative that some people have used is to run windows in a virtual machine and use PCI passthrough to pass through the sound card to the VM. Then, using a patched qemu binary that logs requests to the sound card, all the required verbs can be obtained from the running windows VM. This approach was a bit cumbersome since I failed at the first step of compiling the patched qemu. I am not new to PCI passthrough since I am doing this already for my graphics card on my server, but this was a bit too much. I might have spent more time on this though if the current attempt would have been unsuccessful.
So sound was finally working. The above approach sounds easy, but it took my quite some time to find out that I had to use the legacy driver. Initially, I didn’t and found out only later that patch support is not included in sof yet, see this github issue. It also didn’t help that I made a typo in an earlier attempt and used option instead of options in the modprobe configuration file for using the legacy driver, so that in this earlier attempt my setting was ignored.
Step 3: patch the kernel driver
After having done step 2 I thought it was time to ask for some support by the SOF project because it seemed like I was really close to a fully working setup. Having all the detailed configuration figured out all that was needed is incorporating it into the standard driver. Hopefully then the built-in digital mic would also start to work again. See this github issue. Now everything went fast, I was almost in a direct conversation with Pierre-Louis Bossart from the sof project and before I knew it he had made a patch that could be tested.
Figuring out how to build this patch took a little bit of googling, but it wasn’t hard and before I knew it everything was working. Remember to remove or comment out all the custom settings in /etc/modprobe.d before testing. Now, with a little bit of luck, the patch will be accepted and in the future I can install any new linux kernel and have audio work straight out of the box. This is clearly an example of how open source is supposed to work!
Edit 2023-02-20: the patch was accepted.