[PATCH v4 0/2] ALSA: usb-audio: the Topping M62's vendor controls

From: Mikhail Gavrilov

Date: Sun Aug 23 2026 - 18:30:05 EST


v4 answers the automated review of v3. One of its three findings led to
a change; the other two do not hold, and I would rather say why here
than leave the question hanging for a human reader of the thread.

The change is in 2/2. The driver marks its elements USB_MIXER_BESPOKEN,
which opts them out of the mixer core's restore_mixer_value(), so
restoring across a suspend became this driver's own business. For the
gains that is covered -- the device announces them and the cache
re-syncs by itself -- but a source selector is never reported by the
device at all, so nothing covered it: if the card had come up on its
own defaults while the host slept, the driver's idea of the selector
would have been silently wrong, and writing the remembered value back
would have looked like no change and done nothing. The resume path now
writes the chosen value again.

Said plainly, because it matters for how you weigh it: I did not
observe that. This card has a battery, and with the headphone selector
on Playback 3/4 and music playing into that bus, a full suspend and
wake brought the sound straight back untouched. The change closes a gap
this driver opened by opting out of the core's restore, not a fault
seen on the hardware.

The two findings I am not acting on both concern a control callback
using a freed private structure during disconnect. The ALSA core
already excludes it. snd_ctl_elem_read() and snd_ctl_elem_write() take
snd_power_ref_and_wait(card) around the callback;
snd_card_disconnect() ends with snd_power_sync_ref(card), which waits
until every such reference is dropped; and in usb-audio's disconnect,
snd_card_disconnect() runs before usb_audio_disconnect_components()
reaches snd_usb_mixer_disconnect() and hence this driver's
private_free(). So no callback can be inside the driver when the
structure is freed, and none can enter afterwards --
snd_power_ref_and_wait() sees card->shutdown and returns -ENODEV. The
observation that the controls themselves live until snd_card_free() is
correct; the access path to them is closed earlier.

Nothing else changed since v3. The questions in the v2 cover letter --
about a third form in which snd-usb-audio would register the hid_driver
itself, and about a control that can be written but not read -- still
stand.

Tested on the hardware: values arrive by themselves after probe, a
front panel knob still reaches the driver ten minutes later and after a
suspend and resume cycle, a write reaches the analogue stage (one
source recorded at gain 30 and at gain 60 differs by 30.4 dB against
the 30.0 dB the taper table predicts), the audible selector test
passes, unbind and bind again works, and alsactl stores and restores
these controls without complaint. On a KASAN and lockdep kernel,
including unplug while a stream was running; no reports.

Mikhail Gavrilov (2):
ALSA: usb-audio: expose the Topping M62's analogue gains as mixer
controls
ALSA: usb-audio: let the M62's outputs say what they listen to

MAINTAINERS | 6 +
drivers/hid/hid-ids.h | 3 +
drivers/hid/hid-quirks.c | 2 +
sound/usb/Makefile | 1 +
sound/usb/card.c | 19 +
sound/usb/mixer_quirks.c | 5 +
sound/usb/mixer_topping.c | 734 ++++++++++++++++++++++++++++++++++++++
sound/usb/mixer_topping.h | 7 +
sound/usb/usbaudio.h | 4 +
9 files changed, 781 insertions(+)
create mode 100644 sound/usb/mixer_topping.c
create mode 100644 sound/usb/mixer_topping.h


base-commit: 2709dd5ae32f0828f386327c76bba9f39f63a1c6
--
2.55.0