Linux Input/HID development
 help / color / mirror / Atom feed
From: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
To: tiwai@suse.de
Cc: tiwai@suse.com, perex@perex.cz, jikos@kernel.org,
	bentiss@kernel.org, linux-sound@vger.kernel.org,
	linux-input@vger.kernel.org, linux-kernel@vger.kernel.org,
	Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
Subject: [RFC PATCH v6 0/2] the Topping M62's vendor controls, on the component framework
Date: Fri,  4 Sep 2026 21:58:46 +0500	[thread overview]
Message-ID: <20260904165848.3940603-1-mikhail.v.gavrilov@gmail.com> (raw)
In-Reply-To: <20260904162236.3212370-1-mikhail.v.gavrilov@gmail.com>

This is the experiment Takashi suggested in the v8 thread: an
individual HID driver joined to snd-usb-audio through the component
framework, instead of a mixer quirk that claims the HID interface for
itself. It is posted as an RFC rather than as v9 because v8 is not
withdrawn -- it remains the alternative, and the choice between the two
is the question this series exists to answer.

I said this morning that I would hold this until the questions in that
thread were answered. I am sending it anyway, because a patch gets a
better answer than a question does, and because the last of those
questions answered itself: the correction I sent a few hours ago
proposed deferring the controls until the card reports, and working out
how that lands in code showed why it cannot -- which is in the section
below. The only question still genuinely open is the HID one, and it
touches one line.

Changes since v5:
 
  - topping_master_bind() warned when it could not find its context,
    treating that as impossible. It is not. devres_release_all() moves
    every node off the device before it calls a single release, so
    between a failed probe starting to unwind and the teardown action
    running, the context is gone while the aggregate is still
    registered -- and a HID component arriving in that window takes
    component_mutex first and reaches the bind. The window is narrow
    but it is legitimate, and on a kernel with panic_on_warn the WARN
    would take the machine down for it.
 
    It now returns -EPROBE_DEFER instead, which is what the situation
    actually is: the master is going away, the component came at the
    wrong moment, and it should come back. The framework does not log
    that return, and the HID probe is retried once the audio side is
    back.
 
    The bot described the window as opening in devm_release_action(),
    which unlinks only the action's own node and leaves the context in
    place; the ordinary teardown road is therefore safe. The window is
    real on the other road, which is what this fixes.

What the shape buys, measured rather than argued:

  - card.c is not touched at all. The v8 series had to add
    snd_usb_claim_iface() and snd_usb_release_iface() there, and had a
    defect I reported separately: an interface claimed and marked
    USB_AUDIO_IFACE_UNUSED never gets told to wind down, because
    usb_audio_disconnect() returns at its first line. With no claim
    there is no such interface and the defect has nothing to attach
    to. Watching the wire with usbmon: unbind the audio interface and
    the keepalive stops. In v8 it kept going.

  - the hid_ignore_list entry goes away, so hidraw stays available.
    That matters because five of the card's functions -- the mixer
    matrix, the mutes, the loopback routing, the input power and the
    EQ -- are reachable only through the vendor protocol, and v8 made
    them unreachable from userspace as the price of the quirk.

  - two M62s on one host bind to their own cards. The match is by
    descent from the shared USB device, and it holds: gains set on one
    do not appear on the other, and unplugging one leaves the other's
    controls in place. The quirk road could not be tested for this at
    all.

On the timing worry from that thread: it does not bite on an ordinary
plug. The master goes up from snd_topping_init() inside
snd_usb_create_mixer(), so the bind is synchronous and the controls
exist before try_to_register_card() -- the same ordering as v8. From
HID probe to component bind, 54 to 57 ms across five replugs. Only a
module reload onto a live card adds controls after registration, and
there a desktop mixer does not follow the renumbered elements until
wireplumber is restarted. That is a real wart and I have not found a
way around it that is worth the code.

What the card does and does not report

I got this wrong twice in the v8 thread and would rather state it
plainly here, since the design follows from it.

After a subscribe the card reports itself in two waves: jacks at about
0.9 s, then at about 5.2 s the jacks again plus the output mutes plus
the gain of every input whose jack is present. Every turn of a
front-panel knob is reported as it happens, gains and output volumes
alike. What is never reported is a source selector, because the card
reports events and a selector has no front-panel control, so no event
can exist; and an output volume before anyone has touched it, because
it is a setting rather than a physical fact.

So five of the nine controls have a source of truth on the card, two
have one only after a hand moves them, and two never do.

That looked at first like an argument for deferring the controls until
the first report lands, so that a value read at connect would be the
panel's rather than something restored over it. I have not done that,
and here is why: alsactl restores once, at card add, and does not
come back for elements that appear later. Deferring would therefore
trade an accurate value for five controls against no restore at all
for nine, and would wait forever for an input with nothing plugged
into it -- which on a five-input card is the normal case.
The controls are published at bind, as in v8, and the value at
connect is the restored one.

Open question, not blocking the review

hid_hw_open() sets intf->needs_remote_wakeup, and usbhid offers no way
to take input reports without it. This card does not advertise remote
wakeup (bmAttributes 0xc0, no power/wakeup node), so that forbids
runtime suspend to the whole device -- undoing something an earlier
revision of the v8 series had to fix. The driver clears the flag after
opening, with a comment saying so, because it resynchronises on resume
and has no use for a device-initiated wakeup. Jiri and Benjamin have
been asked whether that is acceptable or whether usbhid should offer
something; the question is in the same thread and unanswered. If the
answer is that the clear must go, HID_CONNECT_DRIVER replaces
HID_CONNECT_HIDRAW and the hidraw node goes with it.

Tested

Fedora, 7.3.0-rc1-bc35965f6940 plus this series, with KASAN,
PROVE_LOCKING and UBSAN enabled. One M62, firmware V87.05.45.48.27,
and a second of the same for the two-card test. Everything below was
run after the fixes listed above, not before them.
 
All nine controls read and written from amixer and from the front
panel, values cross-checked against the panel.
 
One hundred cycles of module load and unload against a live card,
which is the path the fixes touch: the controls come and go while the
meter stream keeps arriving, so .raw_event() runs against a set of
controls that is being taken apart. No splat and no lockdep complaint,
including on the lock order the first fix introduces -- m62->lock is
now held across snd_ctl_notify(), which takes the card's
controls_rwlock inside it.
 
An audio-side unbind and rebind, exercising topping_unbind() through
the master rather than through the HID driver's own remove.
 
The cable pulled out of a card while a control was being written in a
loop. That produces a run of failed writes and then the disconnect,
and after the last fix it does so without a line of complaint each.
 
System suspend and resume: the subscription survives it -- turning a
front-panel knob afterwards still moves the control -- and the
selectors are written back on the way out, as they must be since the
card never reports them.
 
Two cards on one host, on different ports of the same hub: the
component match is by descent from the shared USB device and it holds
-- dmesg shows snd-usb-audio 3-1.3:1.0 binding one HID device and
3-1.4.2:1.0 the other, each card carries its own nine controls, gains
set from one front panel move only that card's controls, and
unplugging one leaves the other's in place.
 
Not tested:
 
  - hibernation, and with it .reset_resume, which shares
    topping_resume() with .resume. This machine is not set up for it:
    there is no resume= on the command line and zram takes swap
    priority, so the attempt logs "PM: Image not found (code -16)" and
    powers off instead of saving an image. That is the same on a stock
    kernel and has nothing to do with this series, but it does mean
    the path is unexercised;
  - kmemleak, compiled in on this system but disabled at boot;
  - a card whose battery has run down;
  - anything on a big-endian host.

Ordering

The HID driver comes first. Between the two patches it binds, speaks
to the card and creates no controls, which is harmless; the reverse
order leaves a master that never matches, which is equally harmless
but leaves hid-generic making a bogus input device out of the
descriptor in the meantime.

Mikhail Gavrilov (2):
  HID: topping-m62: driver for the M62's vendor controls
  ALSA: usb-audio: bind the Topping M62's vendor controls

 MAINTAINERS                   |   9 +
 drivers/hid/Kconfig           |  19 +
 drivers/hid/Makefile          |   1 +
 drivers/hid/hid-ids.h         |   3 +
 drivers/hid/hid-quirks.c      |   3 +
 drivers/hid/hid-topping-m62.c | 925 ++++++++++++++++++++++++++++++++++
 sound/usb/Makefile            |   1 +
 sound/usb/mixer_quirks.c      |   5 +
 sound/usb/mixer_topping.c     | 236 +++++++++
 sound/usb/mixer_topping.h     |   7 +
 10 files changed, 1209 insertions(+)
 create mode 100644 drivers/hid/hid-topping-m62.c
 create mode 100644 sound/usb/mixer_topping.c
 create mode 100644 sound/usb/mixer_topping.h

-- 
2.55.0


  parent reply	other threads:[~2026-09-04 16:58 UTC|newest]

Thread overview: 74+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-12 17:10 snd-usb-audio: exposing a vendor HID control channel as mixer controls (Topping M62, 152a:875c) Mikhail Gavrilov
2026-08-13  7:24 ` Takashi Iwai
2026-08-20 15:13   ` [RFC 0/2] Two ways to reach the Topping M62's analogue gains Mikhail Gavrilov
2026-08-20 15:13     ` [RFC 1/2] ALSA: usb-audio: expose the Topping M62's analogue gains as mixer controls Mikhail Gavrilov
2026-08-20 15:13     ` [RFC 2/2] HID: topping: driver for the M62's vendor control channel Mikhail Gavrilov
2026-08-21 11:23     ` [RFC 0/2] Two ways to reach the Topping M62's analogue gains Mikhail Gavrilov
2026-08-23  8:50     ` Takashi Iwai
2026-08-23 14:22     ` [PATCH v2 0/2] ALSA: usb-audio: the Topping M62's vendor controls Mikhail Gavrilov
2026-08-23 14:22       ` [PATCH v2 1/2] ALSA: usb-audio: expose the Topping M62's analogue gains as mixer controls Mikhail Gavrilov
2026-08-23 14:38         ` sashiko-bot
2026-08-23 14:22       ` [PATCH v2 2/2] ALSA: usb-audio: let the M62's outputs say what they listen to Mikhail Gavrilov
2026-08-23 14:38         ` sashiko-bot
2026-08-23 19:48       ` [PATCH v3 0/2] ALSA: usb-audio: the Topping M62's vendor controls Mikhail Gavrilov
2026-08-23 19:48         ` [PATCH v3 1/2] ALSA: usb-audio: expose the Topping M62's analogue gains as mixer controls Mikhail Gavrilov
2026-08-23 20:07           ` sashiko-bot
2026-08-23 19:48         ` [PATCH v3 2/2] ALSA: usb-audio: let the M62's outputs say what they listen to Mikhail Gavrilov
2026-08-23 20:03           ` sashiko-bot
2026-08-23 22:29         ` [PATCH v4 0/2] ALSA: usb-audio: the Topping M62's vendor controls Mikhail Gavrilov
2026-08-23 22:29           ` [PATCH v4 1/2] ALSA: usb-audio: expose the Topping M62's analogue gains as mixer controls Mikhail Gavrilov
2026-08-23 22:46             ` sashiko-bot
2026-08-23 22:29           ` [PATCH v4 2/2] ALSA: usb-audio: let the M62's outputs say what they listen to Mikhail Gavrilov
2026-08-23 22:46             ` sashiko-bot
2026-08-24 20:13           ` [PATCH v5 0/2] ALSA: usb-audio: the Topping M62's vendor controls Mikhail Gavrilov
2026-08-24 20:13             ` [PATCH v5 1/2] ALSA: usb-audio: expose the Topping M62's analogue gains as mixer controls Mikhail Gavrilov
2026-08-24 20:40               ` sashiko-bot
2026-08-24 20:13             ` [PATCH v5 2/2] ALSA: usb-audio: let the M62's outputs say what they listen to Mikhail Gavrilov
2026-08-24 20:25               ` sashiko-bot
2026-08-24 22:31             ` [PATCH v6 0/2] ALSA: usb-audio: the Topping M62's vendor controls Mikhail Gavrilov
2026-08-24 22:31               ` [PATCH v6 1/2] ALSA: usb-audio: expose the Topping M62's analogue gains as mixer controls Mikhail Gavrilov
2026-08-24 22:47                 ` sashiko-bot
2026-08-24 22:31               ` [PATCH v6 2/2] ALSA: usb-audio: let the M62's outputs say what they listen to Mikhail Gavrilov
2026-08-24 22:58                 ` sashiko-bot
2026-08-25  8:56               ` [PATCH v7 0/2] ALSA: usb-audio: the Topping M62's vendor controls Mikhail Gavrilov
2026-08-25  8:56                 ` [PATCH v7 1/2] ALSA: usb-audio: expose the Topping M62's analogue gains as mixer controls Mikhail Gavrilov
2026-08-25  9:12                   ` sashiko-bot
2026-08-25  8:56                 ` [PATCH v7 2/2] ALSA: usb-audio: let the M62's outputs say what they listen to Mikhail Gavrilov
2026-08-25 11:12                 ` [PATCH v8 0/2] ALSA: usb-audio: the Topping M62's vendor controls Mikhail Gavrilov
2026-08-25 11:12                   ` [PATCH v8 1/2] ALSA: usb-audio: expose the Topping M62's analogue gains as mixer controls Mikhail Gavrilov
2026-08-25 11:12                   ` [PATCH v8 2/2] ALSA: usb-audio: let the M62's outputs say what they listen to Mikhail Gavrilov
2026-08-26 18:06                   ` [PATCH v8 0/2] ALSA: usb-audio: the Topping M62's vendor controls Mikhail Gavrilov
2026-09-03  8:30                     ` Takashi Iwai
2026-09-03  9:35                       ` Mikhail Gavrilov
2026-09-03 10:02                         ` Takashi Iwai
2026-09-03 10:19                           ` Mikhail Gavrilov
2026-09-04  0:18                           ` Mikhail Gavrilov
2026-09-04  7:05                             ` Mikhail Gavrilov
2026-09-04 11:26                               ` [RFC PATCH 0/2] the Topping M62's vendor controls, on the component framework Mikhail Gavrilov
2026-09-04 11:26                                 ` [RFC PATCH 1/2] HID: topping-m62: driver for the M62's vendor controls Mikhail Gavrilov
2026-09-04 11:38                                   ` sashiko-bot
2026-09-04 11:26                                 ` [RFC PATCH 2/2] ALSA: usb-audio: bind the Topping " Mikhail Gavrilov
2026-09-04 11:40                                   ` sashiko-bot
2026-09-04 14:11                                 ` [RFC PATCH v2 0/2] the Topping M62's vendor controls, on the component framework Mikhail Gavrilov
2026-09-04 14:11                                   ` [RFC PATCH v2 1/2] HID: topping-m62: driver for the M62's vendor controls Mikhail Gavrilov
2026-09-04 14:21                                     ` sashiko-bot
2026-09-04 14:11                                   ` [RFC PATCH v2 2/2] ALSA: usb-audio: bind the Topping " Mikhail Gavrilov
2026-09-04 14:24                                     ` sashiko-bot
2026-09-04 14:42                                   ` [RFC PATCH v3 0/2] the Topping M62's vendor controls, on the component framework Mikhail Gavrilov
2026-09-04 14:42                                     ` [RFC PATCH v3 1/2] HID: topping-m62: driver for the M62's vendor controls Mikhail Gavrilov
2026-09-04 14:57                                       ` sashiko-bot
2026-09-04 14:43                                     ` [RFC PATCH v3 2/2] ALSA: usb-audio: bind the Topping " Mikhail Gavrilov
2026-09-04 15:11                                       ` sashiko-bot
2026-09-04 15:30                                     ` [RFC PATCH v4 0/2] the Topping M62's vendor controls, on the component framework Mikhail Gavrilov
2026-09-04 15:30                                       ` [RFC PATCH v4 1/2] HID: topping-m62: driver for the M62's vendor controls Mikhail Gavrilov
2026-09-04 15:30                                       ` [RFC PATCH v4 2/2] ALSA: usb-audio: bind the Topping " Mikhail Gavrilov
2026-09-04 15:45                                         ` sashiko-bot
2026-09-04 16:22                                       ` [RFC PATCH v5 0/2] the Topping M62's vendor controls, on the component framework Mikhail Gavrilov
2026-09-04 16:22                                         ` [RFC PATCH v5 1/2] HID: topping-m62: driver for the M62's vendor controls Mikhail Gavrilov
2026-09-04 16:22                                         ` [RFC PATCH v5 2/2] ALSA: usb-audio: bind the Topping " Mikhail Gavrilov
2026-09-04 16:43                                           ` sashiko-bot
2026-09-04 16:58                                         ` Mikhail Gavrilov [this message]
2026-09-04 16:58                                           ` [RFC PATCH v6 1/2] HID: topping-m62: driver for the " Mikhail Gavrilov
2026-09-04 16:58                                           ` [RFC PATCH v6 2/2] ALSA: usb-audio: bind the Topping " Mikhail Gavrilov
2026-09-04 17:16                                             ` sashiko-bot
2026-09-04 17:45                                               ` Mikhail Gavrilov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260904165848.3940603-1-mikhail.v.gavrilov@gmail.com \
    --to=mikhail.v.gavrilov@gmail.com \
    --cc=bentiss@kernel.org \
    --cc=jikos@kernel.org \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-sound@vger.kernel.org \
    --cc=perex@perex.cz \
    --cc=tiwai@suse.com \
    --cc=tiwai@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox