Internal Speaker Of OneXPlayer 2 Pro (8840) In Linux

Background

Internal speaker of OneXPlayer 2 Pro doesn't work. There is a long thread discussing this issue. From this thread, it seems that the AMP isn't initialized correctly. Someone found that the speaker works after rebooting from Windows. So I came out an idea: What if initializing the AMP with Windows in a virtual machine.

PCI passthrough

To let Windows initialize the AMP, I must let the virtual machine access the hardware directly. This will need VFIO driver in the Linux kernel. I unbind the hardware from snd_hda_intel driver, then bind the hardware to vfio-pci driver. After that, the virtual machine can use the hardware.

PCI slot name

Firstly, I should find out the name of the pci slot connected by the audio device.

# lspci -D: always print domain numbers
# grep -i audio: show only audio related hardware
# grep -v Radeon: remove the hdmi audio device
lspci -D|grep -i audio|grep -v Radeon

The output is like:

0000:64:00.6 Audio device: Advanced Micro Devices, Inc. [AMD] Family 17h/19h HD Audio Controller

0000:64:00.6 is the pci slot name.

Bind/unbind vfio-pci driver

  • bind
echo '0000:64:00.6' | sudo tee /sys/bus/pci/drivers/vfio-pci/unbind
echo '0000:64:00.6' | sudo tee /sys/bus/pci/drivers/snd_hda_intel/bind
  • unbind
echo '0000:64:00.6' | sudo tee /sys/bus/pci/drivers/snd_hda_intel/unbind
echo '0000:64:00.6' | sudo tee /sys/bus/pci/drivers/vfio-pci/bind

Create a virtual device with the Windows partition

In the previous research, I found that the internal speaker won't work in a new Windows too. But I have the original Windows partition. Each time I installed Linux on a new machine, I would keep the Windows partition not touching. After some researches, I finally start a vm with the Windows partition. Avoiding to mass the original Windows partition, I used dd to clone the partition.

# I have shrinked the size of the partition to 89GB.
dd if=/dev/nvme0n1p3 of=/var/cache/oxp2p-win11.img

Keep the partition layout

I kept the partition layout of the Windows partition and partitions before it to avoid any implicit issue.

  • Use the following command to print the layout.
fdisk -l /dev/nvme0n1

The output is like:

/dev/nvme0n1p1       2048     206847     204800   100M EFI System
/dev/nvme0n1p2     206848     468991     262144   128M Microsoft reserved
/dev/nvme0n1p3     468992  187191295  186722304    89G Microsoft basic data

A sector equals to 512 bytes.

  • Create an image to simulate those two partitions before the Windows partition.
dd if=/dev/zero of=part1.img bs=512 count=468992
  • Create an image for margin after the Windows partition.
dd if=/dev/zero of=part3.img bs=1M count=100

I don't know why. But it seems there should be some addtitional spaces after the Windows partition.

  • Create a device mapper.

Use losetup to set the image file as a block device, and then use dmsetup to create a mapper.

loop1_file=part1.img
loop2_file=/var/cache/oxp2p-win11.img
loop3_file=part3.img

disk_name=oxp2p-win11

loop1=$(sudo losetup -f)
sudo losetup $loop1 $loop1_file
loop1_size=$(sudo blockdev --getsz $loop1)
loop2=$(sudo losetup -f)
sudo losetup $loop2 $loop2_file
loop2_size=$(sudo blockdev --getsz $loop2)
loop3=$(sudo losetup -f)
sudo losetup $loop3 $loop3_file
loop3_size=$(sudo blockdev --getsz $loop3)


sudo dmsetup create $disk_name <<EOF
0 $loop1_size linear $loop1 0
$loop1_size $loop2_size linear $loop2 0
$(expr $loop1_size + $loop2_size) $loop3_size linear $loop3 0
EOF

Run with qemu

  • Create an empty file for persisting UEFI variables
dd if=/dev/zero conv=sync bs=1M count=4 of=ovmf_vars.fd
  • Run with qemu
# The path of /usr/share/edk2/x64/OVMF_CODE.4m.fd will be different in different distro.
# This should be run after binding the `vfio-pci` driver.
qemu-system-x86_64 -m 4096M -smp 4 -accel kvm -cpu host -drive file=/usr/share/edk2/x64/OVMF_CODE.4m.fd,if=pflash,format=raw,readonly=on -drive file=./ovmf_vars.fd,if=pflash,format=raw -drive file=/dev/mapper/oxp2p-win11,media=disk,format=
raw -device usb-ehci -device usb-kbd -device usb-mouse -device usb-tablet -usb -monitor stdio -device vfio-pci,host=64:00.6
  • Force closing the vm after the sound came out in the login screen.
  • Unbind the vfio-pci driver.

Advance(hda-verb)

TO BE CONTINUED

Reference