• Welcome to ASR. There are many reviews of audio hardware and expert members to help answer your questions. Click here to have your audio equipment measured for free!

I reverse-engineered the DX5 II's control protocol and built a Linux kernel driver - desktop slider now drives the real analogue volume

tcreswick

Member
Joined
Aug 14, 2026
Messages
6
Likes
35
I made a Linux kernel driver for the Topping DX5 II which I've published on Github at tcreswick/topping-dx5ii-linux.

The driver supports:
  • Mute / Unmute
  • Setting volume as real ALSA controls (%age, dB etc)
  • Input selection
  • Output selection
  • PEQ enable/disable
  • PCM filter selection
  • High/Low gain select
The main benefits (if not already obvious!):
  • The operating system volume slider adjusts volume on the DAC, and vice-versa
  • No more setting the OS volume to 100% and leaning over to make a change on the DAC
  • This means easy volume changes using your keyboard keys, and mute key
  • Programmatically change inputs and outputs from the command line (if you want to automate)
Very much a "works for me" initial release, but I thought I'd post here to see if there are any other DX5 Linux users who would like to use it - the included instructions are tested on CachyOS only, but can easily be updated for other distributions if people would find that useful.

It's based on about an hour of reverse engineering the Topping USB HID protocol - documentation for that is now included in the Github repo too, if you want to roll your own implementation.

Feedback welcome!

The amixer output is here, if you want the details on all the 'knobs':

Code:
Simple mixer control 'Master',0
  Capabilities: pvolume pvolume-joined pswitch pswitch-joined
  Playback channels: Mono
  Limits: Playback 0 - 198
  Mono: Playback 114 [58%] [-42.00dB] [on]
Simple mixer control 'PCM Filter',0
  Capabilities: enum
  Items: 'F-1 Minimum Phase' 'F-2 Linear Phase Fast Roll-Off Apodizing' 'F-3 Linear Phase Fast Roll-Off' 'F-4 Linear Phase Fast Roll-Off Low Ripple' 'F-5 Linear Phase Slow Roll-Off' 'F-6 Minimum Phase Fast Roll-Off' 'F-7 Minimum Phase Slow Roll-Off' 'F-8 Minimum Phase Slow Roll-Off Low Dispersion'
  Item0: 'F-1 Minimum Phase'
Simple mixer control 'Gain',0
  Capabilities: enum
  Items: 'Low' 'High'
  Item0: 'Low'
Simple mixer control 'Input Source',0
  Capabilities: cenum
  Items: 'USB' 'Optical' 'Coaxial' 'Bluetooth'
  Item0: 'USB'
Simple mixer control 'Output Mode',0
  Capabilities: enum
  Items: 'ALL' 'HPA ALL' 'LO ALL' 'HPA SE' 'HPA BAL' 'LO SE'
  Item0: 'ALL'
Simple mixer control 'PEQ',0
  Capabilities: pswitch pswitch-joined
  Playback channels: Mono
  Mono: Playback [off]

NB: I wasn't able to figure out how to 'poll' the current status of the device, so at initial startup the driver can be out of sync with the DAC (i.e. it has no way of knowing what the current input, output, PEQ and volume settings are until they are changed). I'm working on this.
 
There's a good chance they used the same protocol, so might only need light modification - I only have a DX5 II here to test. If you want to try it that would be helpful.
 
Very nice, hats off and thanks!

I wonder why Topping used a custom HID protocol, instead of the UAC feature units which would not require any custom driver for the standard features. Maybe due to the non-standard features (EQ etc.)... some GUI control app would have to handle complete control of the device via two different methods - volume via sound API, the extra features via a custom driver or user-space libusb... they needed only one method this way. But then the OS volume controls are not active... always some compromises :-)
 
Yeah in principle I don't hate that they implemented it this way, and clearly was just easier for them for their own engineering - it's just MODBUS over the HID transport, so presumably was just very familiar to the engineers who made it.

Just a shame that they didn't then produce some drivers to do what I've done and/or publish the documentation for the protocol. Having a non-standard implementation is fine if you provide the right adaptors.
 
I made a Linux kernel driver for the Topping DX5 II which I've published on Github at tcreswick/topping-dx5ii-linux.

The driver supports:
  • Mute / Unmute
  • Setting volume as real ALSA controls (%age, dB etc)
  • Input selection
  • Output selection
  • PEQ enable/disable
  • PCM filter selection
  • High/Low gain select
The main benefits (if not already obvious!):
  • The operating system volume slider adjusts volume on the DAC, and vice-versa
  • No more setting the OS volume to 100% and leaning over to make a change on the DAC
  • This means easy volume changes using your keyboard keys, and mute key
  • Programmatically change inputs and outputs from the command line (if you want to automate)
Very much a "works for me" initial release, but I thought I'd post here to see if there are any other DX5 Linux users who would like to use it - the included instructions are tested on CachyOS only, but can easily be updated for other distributions if people would find that useful.

It's based on about an hour of reverse engineering the Topping USB HID protocol - documentation for that is now included in the Github repo too, if you want to roll your own implementation.

Feedback welcome!

The amixer output is here, if you want the details on all the 'knobs':

Code:
Simple mixer control 'Master',0
  Capabilities: pvolume pvolume-joined pswitch pswitch-joined
  Playback channels: Mono
  Limits: Playback 0 - 198
  Mono: Playback 114 [58%] [-42.00dB] [on]
Simple mixer control 'PCM Filter',0
  Capabilities: enum
  Items: 'F-1 Minimum Phase' 'F-2 Linear Phase Fast Roll-Off Apodizing' 'F-3 Linear Phase Fast Roll-Off' 'F-4 Linear Phase Fast Roll-Off Low Ripple' 'F-5 Linear Phase Slow Roll-Off' 'F-6 Minimum Phase Fast Roll-Off' 'F-7 Minimum Phase Slow Roll-Off' 'F-8 Minimum Phase Slow Roll-Off Low Dispersion'
  Item0: 'F-1 Minimum Phase'
Simple mixer control 'Gain',0
  Capabilities: enum
  Items: 'Low' 'High'
  Item0: 'Low'
Simple mixer control 'Input Source',0
  Capabilities: cenum
  Items: 'USB' 'Optical' 'Coaxial' 'Bluetooth'
  Item0: 'USB'
Simple mixer control 'Output Mode',0
  Capabilities: enum
  Items: 'ALL' 'HPA ALL' 'LO ALL' 'HPA SE' 'HPA BAL' 'LO SE'
  Item0: 'ALL'
Simple mixer control 'PEQ',0
  Capabilities: pswitch pswitch-joined
  Playback channels: Mono
  Mono: Playback [off]

NB: I wasn't able to figure out how to 'poll' the current status of the device, so at initial startup the driver can be out of sync with the DAC (i.e. it has no way of knowing what the current input, output, PEQ and volume settings are until they are changed). I'm working on this.
I made a set of functional Ubuntu (26.04 for me) instructions:

### Ubuntu Installation Guide (with Secure Boot)

Ubuntu compiles `usbhid` directly into the kernel and strictly enforces Secure Boot module signing. The standard installation instructions will fail silently or result in a `Key was rejected by service` error.

Follow these adapted steps to successfully compile and load the driver on Ubuntu.

#### 1. Clone the Repository and Install Dependencies

git clone [URL='https://github.com/tcreswick/topping-dx5ii-linux.git](https://github.com/tcreswick/topping-dx5ii-linux.git)']https://github.com/tcreswick/topping-dx5ii-linux.git[/URL]
cd topping-dx5ii-linux
sudo apt update && sudo apt install build-essential linux-headers-$(uname -r) dkms

2. Configure WirePlumber​

sudo mkdir -p /etc/wireplumber/wireplumber.conf.d/
sudo cp conf/wireplumber/51-topping-dx5ii.conf /etc/wireplumber/wireplumber.conf.d/
systemctl --user restart wireplumber pipewire pipewire-pulse

3. Bypass the Default USB Driver via GRUB​

cat conf/modprobe.d/topping-dx5ii.conf
#Take note of the hexadecimal quirk string (e.g., quirks=0xABCD:0x1234:0x00000004).

sudo vim /etc/default/grub
#Locate GRUB_CMDLINE_LINUX_DEFAULT and append the quirk string to the end of the parameters, inside the quotation marks.
[I]#Example:[/I] GRUB_CMDLINE_LINUX_DEFAULT="quiet splash usbhid.quirks=0xABCD:0x1234:0x00000004"
#Save the file and update GRUB:
sudo update-grub

4. Generate and Enroll a Secure Boot Signing Key​

Secure Boot will block the custom module unless it is digitally signed. Generate a Machine Owner Key (MOK) and queue it for enrollment:

sudo mkdir -p /var/lib/shim-signed/mok/
sudo openssl req -new -x509 -newkey rsa:2048 -keyout /var/lib/shim-signed/mok/MOK.priv -outform DER -out /var/lib/shim-signed/mok/MOK.der -nodes -days 36500 -subj "/CN=Ubuntu DKMS MOK/"
sudo mokutil --import /var/lib/shim-signed/mok/MOK.der
#You will be prompted to create a temporary password.
Reboot your computer. Before Ubuntu loads, the MOKManager screen will appear:
  1. Select Enroll MOK -> Continue.
  2. Confirm the enrollment and enter your temporary password.
  3. Select Reboot to boot back into Ubuntu.

5. Fetch Kernel Source and Build DKMS​

Navigate back to the driver directory. Fetch the correct kernel source and pass it to DKMS so it can build and sign the module:

cd topping-dx5ii-linux
src=$(./scripts/fetch-kernel-source.sh)
echo "KSRC=$src" | sudo tee /etc/topping-dx5ii.conf
sudo ./dkms/install-dkms.sh

6. Force Deployment and Update Initramfs​

Force DKMS to deploy the newly signed module over any stale versions, then rebuild the initial ramdisk so the system loads your custom driver on boot:
sudo dkms install -m topping-dx5ii -v 0.1.0 --force
sudo update-initramfs -u

7. Final Reboot and Verification​

Reboot the computer one final time. Verify the driver is working by checking the kernel logs:

dmesg | grep -i topping

You should see hardware mixer enabled.

To test the bidirectional sync, run alsactl monitor 0 and turn the physical volume knob on the DAC.
Mine never worked for this so YMMV.
 
Very nice. Did you consider merging into the kernel mainline? Typically out-of-tree kernel modules die after a while, unfortunately and logically.
 
Very nice. Did you consider merging into the kernel mainline? Typically out-of-tree kernel modules die after a while, unfortunately and logically.

I’m not sure how to do that. Technically topping should be doing this.
 
IME most manufacturers do not care, typically they even refuse to provide technical docs to volunteers.

I would start with asking alsa maintainer Takashi Iwai how to proceed - just give him link to your github and ask for suggestions. Originally all development was in https://lore.kernel.org/alsa-devel/ mailing list, recently https://lore.kernel.org/linux-sound/ is taking over, subsystems gradually move to the centralized kernel.org mailing lists. I would ask at alsa-devel (also which mailing list to use).

When you agree on dir structure of your driver, then you just send patches to the mailing list - there are docs about the procedure plus any good AI (e.g. github copilot) will give you the necessary patch formatting/checking commands.

I have a few drivers and patches in the kernel alsa and it is nothing complicated.
 
IME most manufacturers do not care, typically they even refuse to provide technical docs to volunteers.

I would start with asking alsa maintainer Takashi Iwai how to proceed - just give him link to your github and ask for suggestions. Originally all development was in https://lore.kernel.org/alsa-devel/ mailing list, recently https://lore.kernel.org/linux-sound/ is taking over, subsystems gradually move to the centralized kernel.org mailing lists. I would ask at alsa-devel (also which mailing list to use).

When you agree on dir structure of your driver, then you just send patches to the mailing list - there are docs about the procedure plus any good AI (e.g. github copilot) will give you the necessary patch formatting/checking commands.

I have a few drivers and patches in the kernel alsa and it is nothing complicated.
TCreswick is the real hero here. I just found out how to make Ubuntu obedient. But I do agree. If we could get this to just be integrated with the kernel it’s a huge win.

I used the roon raat also to enable DSD playback. That’s a huge PITA and requires a service to tell pulsewire to lego my device so roon can hit it. But full DSD playback works now for me.
 
IME most manufacturers do not care, typically they even refuse to provide technical docs to volunteers.

I would start with asking alsa maintainer Takashi Iwai how to proceed - just give him link to your github and ask for suggestions. Originally all development was in https://lore.kernel.org/alsa-devel/ mailing list, recently https://lore.kernel.org/linux-sound/ is taking over, subsystems gradually move to the centralized kernel.org mailing lists. I would ask at alsa-devel (also which mailing list to use).

When you agree on dir structure of your driver, then you just send patches to the mailing list - there are docs about the procedure plus any good AI (e.g. github copilot) will give you the necessary patch formatting/checking commands.

I have a few drivers and patches in the kernel alsa and it is nothing complicated.
If you make the connections or want to give him all the notes and GitHub code I’d imagine you could. I think everyone would benefit and maybe they could make this capability and innate one for all dsd DACs
 
Thanks for the Ubuntu notes, and glad to see that someone else found this useful!

I've been quite busy on other things, but had intended to submit it to the mainline kernel in due course, ideally after a few other people have tested it and we know that it's stable, since the kernel maintainers would have no way to verify that it works without the requisite hardware.

I'm not a Ubuntu expert, but I think you can simplify your step 4 to just:

sudo update-secureboot-policy --new-key # no-op if a key already exists
sudo update-secureboot-policy --enroll-key # prompts for password, reboot, MokManager

It's a shame that you have to modify the boot options on Ubuntu - they build usbhid into the kernel rather than as a module.
 
had intended to submit it to the mainline kernel in due course, ideally after a few other people have tested it and we know that it's stable, since the kernel maintainers would have no way to verify that it works without the requisite hardware.
Perfect plan. Typically kernel maintainers do not check the drivers on the given hardware, it's responsibility of the submitter (signed-off-by). Thanks!
 
If @whoopn can verify those Ubuntu instructions, I'll happily update the Github page accordingly for the next person!
 
Last edited:
Back
Top Bottom