Add an HDA side codec driver for the AWINIC AW88399 smart amplifier,
enabling its use as a companion amplifier on HDA systems where the
chip is connected via I2C to the host and driven alongside a primary
HDA codec (such as Realtek ALC287).
The driver is structured after the existing side codec drivers:
* aw88399_hda_i2c.c: I2C bus driver matching ACPI HID "AWDZ8399" and
serial-multi-instantiate device name "aw88399-hda".
Creates the regmap and passes it to the shared probe function,
following the CS35L41/CS35L56/TAS2781 pattern.
* aw88399_hda.c: Core driver implementing HDA component binding,
playback hooks (using the shared library's start/stop functions),
ACPI subsystem ID retrieval, and runtime/system power management.
Includes per-model quirk infrastructure using ACPI subsystem ID
matching; the quirk table is empty in this patch and populated in
the next patch along with the corresponding Realtek fixups that
activate the driver.
The driver includes <sound/aw88399.h> for shared definitions and
depends on SND_SOC_AW88399_LIB for chip initialization, firmware
loading, and playback control, avoiding any dependency on the full
ASoC codec module.
Tested-by: Nadim Kobeissi <nadim@symbolic.software>
Tested-by: Xia Yun'an <imitoy@imitoy.top>
Tested-by: Munzir Taha <munzirtaha@gmail.com>
Co-developed-by: Yakov Till <yakov.till@gmail.com>
Signed-off-by: Yakov Till <yakov.till@gmail.com>
Signed-off-by: Marco Giunta <marco_giunta@outlook.it>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/DS7PR19MB77247D67E739956AA4611ACEFCCA2@DS7PR19MB7724.namprd19.prod.outlook.com
snd_hda_add_new_path() returns NULL when no path exists between the
given NIDs, but olpc_xo_update_mic_pins() passes dc_mode_path
straight to snd_hda_activate_path() which dereferences it without
checking. Add the missing NULL guards, same as the local path
variable already has in the same function.
Signed-off-by: wangdicheng <wangdicheng@kylinos.cn>
Link: https://patch.msgid.link/20260729070935.548050-2-wangdich9700@163.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Add subsystem ID 103c:88ed to the existing HP Victus 16-e0xxx
mute LED quirk list.
The HP Victus 16-e0xxx with subsystem ID 103c:88ed uses the same
mute LED coefficient configuration as the already supported
103c:88eb variant.
The mute LED was verified by manually toggling coefficient index
0x0b (bit 3) using hda-verb. After adding the quirk, the LED is
registered as hda::mute and follows the audio mute state.
Signed-off-by: André Pragosa <pragosa512@gmail.com>
Link: https://patch.msgid.link/20260728221129.14680-2-pragosa512@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
The C-Media CM6206 (0d8c:0102) truncates the three-byte sample rate it
returns for UAC_GET_CUR to its two low bytes. After the rate has been
set to 96000 (0x017700) the device reports back 30464 (0x007700).
At probe time the driver initializes every altsetting to its maximum
rate, so altsetting 5 is set to 96000 and the warning appears on each
plug-in, before anything has opened the device:
usb 3-1.3: 1:5 Set sample rate 96000, clock 0
usb 3-1.3: current rate 30464 is different from the runtime rate 96000
That altsetting is the one parse_audio_format_rates_v1() already fixes
up for this chip, so this affects every CM6206.
Only the read-back is broken, the rate itself is applied: a 1 kHz sine
rendered at 96 kHz is recovered at 1000.2 Hz, and a silent fallback to
48000 would have been reported as 0x00bb80 rather than as the low half
of the requested rate.
Add a QUIRK_FLAG_GET_SAMPLE_RATE entry for the device so the read-back
is skipped. Setting the same flag through the quirk_flags module
parameter makes the warning disappear while the 96000 init still
happens.
Signed-off-by: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
Link: https://patch.msgid.link/20260728222239.62749-1-mikhail.v.gavrilov@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
snd_usb_handle_sync_urb() scales received sync packet sizes by the sender's
stride and stores the result directly in out_packet->packet_size[i]. If a
connected USB device sends an oversized sync packet, this frame count can
exceed ep->maxframesize.
The un-clamped frame count then propagates to the playback endpoint queue,
potentially driving packet transfers beyond the endpoint's hardware frame
limits.
Cap the calculated frame count against ep->maxframesize in
snd_usb_handle_sync_urb() to prevent oversized packets from entering the
playback queue.
Fixes: 28acb12014 ("ALSA: usb-audio: use sender stride for implicit feedback")
Cc: stable@vger.kernel.org
Assisted-by: Jetski:Gemini-3.6-Flash
Signed-off-by: Sonali Pradhan <sonalipradhan@google.com>
Link: https://patch.msgid.link/20260728202432.2354994-1-sonalipradhan@google.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
When a USB audio endpoint requests full packet transfers via the fill_max
descriptor flag, data_ep_set_params() promotes ep->curpacksize to
ep->maxpacksize. However, maxsize is left at the original sample-rate
derived value.
Since u->buffer_size is allocated as maxsize * packets, the resulting
DMA buffer is far too small for the requested transfer length. When the
USB host controller streams up to curpacksize bytes per packet, it writes
past the end of the buffer via DMA, corrupting kernel heap memory.
Update maxsize to curpacksize when fill_max is set so that the allocated
DMA buffer size matches the actual transfer request size.
[ changed to reassign maxsize only when ep->fill_max is set -- tiwai ]
Fixes: 8fdff6a319 ("ALSA: snd-usb: implement new endpoint streaming model")
Cc: stable@vger.kernel.org
Assisted-by: Jetski:Gemini-3.6-Flash
Signed-off-by: Sonali Pradhan <sonalipradhan@google.com>
Link: https://patch.msgid.link/20260728201716.2347726-1-sonalipradhan@google.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This USB Audio device (0x1e0b:0xd01e) exhibits audio stuttering
during boot when playing audio. Once the system is fully booted,
playback is normal.
The device reports its isochronous endpoints with the Asynchronous
sync type (bmAttributes = 0x03), which causes the driver to
calculate nurbs = min(max_urbs, ...) = 3, providing only ~16ms
of buffering. During boot, the higher system scheduling jitter
(e.g., from init scripts, device enumeration, and driver probing)
can exceed this buffer depth, causing audible stuttering.
This patch adds a device-specific quirk (QUIRK_FLAG_PLAYBACK_URB_FIXUP)
that applies two changes for this device:
1. Forces nurbs to MAX_URBS (12), providing sufficient buffering
2. Sets URB_ISO_ASAP flag for more consistent xHCI scheduling
Both changes are required together for stable boot-time playback:
- The larger buffer absorbs scheduling jitter during boot
- URB_ISO_ASAP ensures consistent URB submission timing, preventing
the xHCI scheduler from introducing variable delays
Test methodology:
- Without patch: reboot and play audio → stuttering audible in all
tests (reproduced consistently across multiple attempts)
- With nurbs=8 only: occasional minor stuttering observed after
multiple tests (insufficient buffer depth)
- With full patch (nurbs=12 + URB_ISO_ASAP): reboot and play audio
→ no stuttering observed (tested in 10+ reboot cycles without
reproducing the issue)
Signed-off-by: Zhang Heng <zhangheng@kylinos.cn>
Link: https://patch.msgid.link/20260728111309.1271834-1-zhangheng@kylinos.cn
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Add USB mixer mapping quirk for later revisions of the Corsair Virtuoso
headset with USB IDs 0x1b1c:0x0a43 (wired) and 0x1b1c:0x0a44
(wireless). These devices exhibit the same mixer label collision as
earlier Virtuoso variants: all controls are labelled "Headset", causing
applications like PulseAudio to move the sidetone control instead of
the main playback volume.
Signed-off-by: Robert Abrahamse <denobyte2@gmail.com>
Link: https://patch.msgid.link/20260728140314.11601-1-denobyte2@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
snd_pcm_drain() on a linked stream parks an on-stack wait entry on the
drained peer's runtime->sleep, and after schedule_timeout() removes it
only if that peer is still found in the caller's group. If group
membership changes during the wait and the sleep ends by signal or
timeout (so autoremove_wake_function() does not run), finish_wait() is
skipped and snd_pcm_drain() returns with the entry still queued on that
stream's sleep list; a later wake_up() then walks a freed stack frame.
This is reachable by unlinking either the drained or the draining stream.
Unlike the close path (snd_pcm_drop() -> snd_pcm_post_stop()),
snd_pcm_unlink() never wakes the sleep queues. Wake every group member
under the group lock before the membership change, so a linked drainer is
released and drops its entry while the streams are still grouped.
The window was opened when snd_pcm_link_rwsem stopped being held across
the wait and the removal became conditional on group membership (see
Fixes). The later switch to finish_wait() kept that conditional removal,
so the signal/timeout case remained.
Fixes: f57f3df03a ("ALSA: pcm: More fine-grained PCM link locking")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5
Signed-off-by: Norbert Szetei <norbert@doyensec.com>
Link: https://patch.msgid.link/A0705100-D10B-4286-9980-0142ABEEAD51@doyensec.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
The HP Dragonfly Folio G3 2-in-1 also ships with PCI SSID 103c:8a05.
On this unit the ALC245 codec reports subsystem id 103c:8a06 - the SSID
that is already covered by commit 0a10faad5c ("ALSA: hda/realtek: add
quirk for HP Dragonfly Folio G3 2-in-1") - while the PCI SSID that
SND_PCI_QUIRK matches against is 103c:8a05:
snd_hda_codec_alc269 ehdaudio0D0: ALC245: picked fixup for PCI SSID 103c:8a05
cs35l41-hda spi1-CSC3551:00-cs35l41-hda.0: CS35L41 Bound - SSID: 103C8A06
The existing entry therefore never applies here, the four CS35L41
amplifiers on SPI are not registered and the internal speakers stay
silent.
Add the same fixup that the 8a06 entry uses: the four amplifiers bind
and the speaker mute LED (codec GPIO 0x04) works.
Signed-off-by: Michael Diesen <michael.diesen@posteo.de>
Link: https://patch.msgid.link/20260727091920.4634-1-michael.diesen@posteo.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Lenovo Legion 7 15ASH11 with AMD RYZEN AI MAX+ 392 (Strix Halo, ACP
7.0) uses Realtek ALC287 series codec. Its audio subsystem adopts a
hardware design similar to that of the Yoga Pro 7 15ASH11.
It shares PCI SSID 17aa:38f9 with Thinkbook 16P Gen5.
Therefore, use HDA_CODEC_QUIRK to apply ALC287_FIXUP_LENOVO_YOGA_PRO7
for identification.
After added the HDA_CODEC_QUIRK quirk special for Lenovo Legion 7
15ASH11, the mic mute LED works well.
Signed-off-by: Jackie Dong <xy-jackie@139.com>
Link: https://patch.msgid.link/20260727080048.13254-1-xy-jackie@139.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
ASoC: Add AW88399 HDA side codec driver for Lenovo Legion
In order to support AW88399 HDA side codec used on the Lenovo Legion we
need updates to it's ASoC driver.
snd_timer_close_locked() marks an instance with SNDRV_TIMER_IFLG_DEAD
and returns early when the flag is already set, but the flag is never
cleared again. A completed close ends in remove_slave_links(), which
leaves timeri->timer NULL, so a second close is already harmless through
the timer == NULL path; the early return can only be reached by an
instance that was opened again in between. For such an instance the
close unlinks nothing, so snd_timer_instance_free() frees an object that
is still on timer->open_list_head, still on snd_timer_master_list if it
was opened with a slave key, still owns any adopted slaves, and still
holds its timer and module references.
snd_seq_timer_open() reopens an instance exactly like that: it retries
its fallback open on the same object after a failure that has already
run snd_timer_close_locked() internally. An unprivileged user with
access to /dev/snd/timer and /dev/snd/seq can force that failure, since
snd_timer_check_master() returns -EBUSY when a pending slave matches the
new master's (slave_class, slave_id) key and the target timer has
reached max_instances, and SNDRV_TIMER_IOCTL_SELECT with dev_class =
SNDRV_TIMER_CLASS_SLAVE keeps the caller-supplied dev_sclass, so a
sequencer queue's key can be forged. The freed instance is afterwards
dereferenced by any further snd_timer_open() on that timer, by
snd_timer_check_slave(), and by /proc/asound/timers, which faults on the
stale ti->owner pointer.
The flag only has to be visible while the close is in progress, which is
all its other users need. Clear it in remove_slave_links(), under the
same timer->lock that sets it, once the instance is off every list.
Fixes: da3039e91d ("ALSA: timer: Forcibly close timer instances at closing")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5
Signed-off-by: Norbert Szetei <norbert@doyensec.com>
Link: https://patch.msgid.link/CA41AA48-75BF-45E9-A36D-3A5D2F124F60@doyensec.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
The Infinix INBOOK X3 Slim (ALC269VB, subsystem 0x2782:0250) has its
internal speakers wired to pin 0x1b, but the BIOS pin configuration
table declares 0x1b as "no physical connection" (0x411111f0). It instead
declares pin 0x14 as the internal speaker, although nothing is connected
to 0x14.
As a result the internal speakers are silent under Linux while the
headphone jack works correctly. The codec output path to 0x14 is fully
open (DAC assigned and streaming, mixer and pin unmuted, EAPD asserted),
so the failure is silent with no error reported. The speakers work under
Windows, where the vendor driver supplies its own pin table.
Add a fixup that disables the unconnected pin 0x14 and declares pin
0x1b as the internal speaker.
Reusing the existing ALC269VC_FIXUP_INFINIX_Y4_MAX was tried first, since
it also remaps 0x1b to an internal speaker. It is not sufficient here: it
leaves 0x14 declared, so autoconfig finds two line_outs
line_outs=2 (0x14/0x1b/0x0/0x0/0x0) type:speaker
and binds the primary "Speaker" control to the unconnected pin 0x14 while
demoting the working speaker at 0x1b to "Bass Speaker". Audio is audible
that way, but the volume and mute controls a desktop actually uses end up
attached to a pin that is not wired to anything. Disabling 0x14 is what
produces a single correct Speaker output.
Verified on the affected machine: with the corrected pin
configuration the driver's autoconfig reports
line_outs=1 (0x1b/0x0/0x0/0x0/0x0) type:speaker
both channels play, headphone auto-mute switches correctly in both
directions, and audio survives codec runtime suspend (D3) and resume.
Signed-off-by: Gunal Seenivasagan <gunal2002@gmail.com>
Link: https://patch.msgid.link/20260726085715.229802-1-gunal2002@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
snd_usbmidi_akai_output() computes its fill-loop bound
buf_end = ep->max_transfer - MAX_AKAI_SYSEX_LEN - 1;
as a signed int, so a small device-advertised bulk-OUT max_transfer
makes buf_end negative. The loop guard then compares the u32
urb->transfer_buffer_length against that negative int: the usual
arithmetic conversion turns buf_end into a large unsigned value, so the
guard stays true and each iteration keeps appending SysEx framing and
payload bytes past the end of the URB transfer buffer, which is only
max_transfer bytes long.
A USB device that advertises a tiny bulk-OUT endpoint can therefore
trigger an attacker-length- and content-controlled heap out-of-bounds
write when a process writes to the created /dev/snd/midiC*D* node.
Return early when there is no room for even one SysEx, so the loop is
never entered with a bound that would wrap. The loop is the last
statement of the function, so bailing out is equivalent to it not
running.
Discovered by XBOW, triaged by Baul Lee <baul.lee@xbow.com>
Fixes: 4434ade8c9 ("ALSA: usb-audio: add support for Akai MPD16")
Suggested-by: Takashi Iwai <tiwai@suse.de>
Reported-by: Federico Kirschbaum <federico.kirschbaum@xbow.com>
Reported-by: Baul Lee <baul.lee@xbow.com>
Cc: stable@vger.kernel.org
Signed-off-by: Baul Lee <baul.lee@xbow.com>
Link: https://patch.msgid.link/20260726074500.50145-1-baul.lee@xbow.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
snd_rme_digiface_read_status() reads a four-word status block from the
device into an uninitialised on-stack __le32 buf[4] and, whenever the
vendor control-IN transfer does not return a negative error, copies all
four words into the caller's status[].
snd_usb_ctl_msg() copies the full requested size back into the caller's
buffer regardless of how many bytes the data stage actually delivered:
buf = kmemdup(data, size, GFP_KERNEL);
err = usb_control_msg(dev, pipe, request, requesttype,
value, index, buf, size, timeout);
memcpy(data, buf, size);
usb_control_msg() returns the transferred length on a short control-IN,
which is a non-negative value, and writes only that many bytes. The
remainder of the copy back is the kmemdup()ed image of the caller's
buffer, so a device answering with a short data stage leaves the
trailing words of buf[] holding leftover kernel stack. The only guard
in the caller is err < 0, so those words are stored into status[].
They then reach user space: snd_rme_digiface_get_status_val() selects a
16-bit halfword of status[] per the control's reg/mask, and the eight
Digiface status controls together expose the whole 16-byte frame to an
unprivileged reader of /dev/snd/controlC*.
Zero-initialise the buffer so a short read yields zeros instead of stack
residue. This mirrors snd_rme_get_status1(), which already clears its
output word before the same kind of vendor read.
Discovered by XBOW, triaged by Baul Lee <baul.lee@xbow.com>
Fixes: 611a96f6ac ("ALSA: usb-audio: Add mixer quirk for RME Digiface USB")
Reported-by: Federico Kirschbaum <federico.kirschbaum@xbow.com>
Reported-by: Baul Lee <baul.lee@xbow.com>
Cc: stable@vger.kernel.org
Signed-off-by: Baul Lee <baul.lee@xbow.com>
Link: https://patch.msgid.link/20260726065020.46070-1-baul.lee@xbow.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
snd_ump_attach_legacy_rawmidi() allocates the legacy conversion array
ump->out_cvts and, on the snd_rawmidi_new() error path, frees it with
kfree() but leaves ump->out_cvts pointing at the freed memory. When the
endpoint is later torn down, snd_ump_endpoint_free() frees ump->out_cvts
a second time, resulting in a double free.
The host snd-usb-audio driver attaches the legacy rawmidi for any USB
MIDI 2.0 (UMP) device, so a device that makes snd_rawmidi_new() fail
reaches this path on enumeration.
Clear ump->out_cvts after freeing it on the error path so it is not
freed again during teardown.
Discovered by XBOW, triaged by Baul Lee <baul.lee@xbow.com>
Fixes: 33cd763078 ("ALSA: ump: Export MIDI1 / UMP conversion helpers")
Reported-by: Federico Kirschbaum <federico.kirschbaum@xbow.com>
Reported-by: Baul Lee <baul.lee@xbow.com>
Cc: stable@vger.kernel.org
Signed-off-by: Baul Lee <baul.lee@xbow.com>
Link: https://patch.msgid.link/20260726051633.41206-1-baul.lee@xbow.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
create_midi2_ump() registers a card-owned snd_ump_endpoint and stores a
back-pointer to its per-interface snd_usb_midi2_ump object in
ump->private_data, but it never installs an ump->private_free hook and
never clears that pointer.
If a later step of snd_usb_midi_v2_create() fails, its error path calls
free_all_midi2_umps(), which kfree()s the snd_usb_midi2_ump object while
the already-registered endpoint keeps pointing at it. The created
/dev/snd/umpC*D* node stays exposed, so the first operation of any UMP
open, ump_to_endpoint(), dereferences the dangling ump->private_data and
reads rmidi->eps[dir] out of freed memory.
A malicious USB MIDI 2.0 device that makes creation fail after the
endpoint is registered can thus trigger a slab use-after-free read on a
subsequent open of the UMP node.
Clear the endpoint's back-pointer before freeing the object, and let
ump_to_endpoint() tolerate a NULL private_data so the open/close/trigger
callbacks fail cleanly (their callers already handle a NULL endpoint)
instead of dereferencing a stale pointer.
Discovered by XBOW, triaged by Baul Lee <baul.lee@xbow.com>
Fixes: ff49d1df79 ("ALSA: usb-audio: USB MIDI 2.0 UMP support")
Reported-by: Federico Kirschbaum <federico.kirschbaum@xbow.com>
Reported-by: Baul Lee <baul.lee@xbow.com>
Cc: stable@vger.kernel.org
Signed-off-by: Baul Lee <baul.lee@xbow.com>
Link: https://patch.msgid.link/20260726051337.41124-1-baul.lee@xbow.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
The Acer Nitro 5 AN515-46 (SSID 1025:159e, Realtek ALC287) has a combo
headset jack whose microphone does not work out of the box: the BIOS
leaves pin 0x19 unconfigured, so no headset mic is created.
Apply ALC2XX_FIXUP_HEADSET_MIC, the same fixup already used by the
sibling models AN515-57 (1025:1539) and AN517-55 (1025:1597), which
makes the headset microphone work correctly.
Tested on an Acer Nitro 5 AN515-46 by overriding the model via a patch
firmware with model=alc2xx-fixup-headset-mic.
Signed-off-by: Marcos Paulo Medeiros <maarcospm1996@gmail.com>
Link: https://patch.msgid.link/20260725214131.25872-1-maarcospm1996@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Setting up the interface when suspended/resuming fails on this card.
Adding a reset and delay quirk will eliminate this problem.
Note: This device's VID conflicts with Apple's (0x05ac).
usb 1-1: New USB device found, idVendor=05ac, idProduct=110b
usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 1-1: Product: Q2A
usb 1-1: Manufacturer: JKY Technology
usb 1-1: SerialNumber: 330270D2251225
Suggested-by: Rong Zhang <i@rong.moe>
Signed-off-by: Lianqin Hu <hulianqin@vivo.com>
Reviewed-by: Rong Zhang <i@rong.moe>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/TYUPR06MB6217566CFD33F57D3AE46816D2CF2@TYUPR06MB6217.apcprd06.prod.outlook.com
The lx6464es driver advertises both 16-bit and packed 24-bit PCM formats,
but lx_trigger_start() and lx_interrupt_request_new_buffer() calculate the
DMA period size as runtime->period_size * runtime->channels * 3. That is
only correct for the packed 24-bit formats.
For 16-bit streams the driver submits buffers that are 50% larger than the
actual ALSA period and advances the DMA address by the same wrong amount.
For example, with 2 channels, 256 frames and 4 periods, the third buffer
already extends beyond the ALSA buffer and the fourth buffer starts outside
it.
Use snd_pcm_lib_period_bytes() so the byte count matches the runtime
format, channel count and period size.
Fixes: 02bec49045 ("ALSA: lx6464es - driver for the digigram lx6464es interface")
Cc: stable@vger.kernel.org
Signed-off-by: Xu Rao <raoxu@uniontech.com>
Link: https://patch.msgid.link/8BB12E8D92A7CDBA+20260723085710.2567463-1-raoxu@uniontech.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
A userspace-driven ALSA timer (SND_UTIMER) lets an unprivileged user set
the backing snd_timer's hardware resolution to an arbitrary 64-bit value
via SNDRV_TIMER_IOCTL_CREATE. snd_utimer_create() only rejects zero.
When such a timer is bound to a sequencer queue, initialize_timer()
computes the tick period as
tmr->ticks = 1000000000 / (r * freq);
where r is that user-controlled resolution and freq is the sequencer
update rate in Hz, clamped to MIN_FREQUENCY..MAX_FREQUENCY (10..6250).
A resolution of 2^63 makes the 64-bit product r * freq wrap to zero for
any even freq, including DEFAULT_FREQUENCY (1000), so the division faults
with a divide-by-zero.
The division runs under tmr->lock with interrupts disabled, so the oops
leaves the spinlock held and hangs the CPU. It is reachable by an
unprivileged user with access to /dev/snd/timer and /dev/snd/seq.
Oops: divide error: 0000 [#1] SMP KASAN PTI
CPU: 7 UID: 1000 PID: 456 Comm: alsa_seq_utimer Not tainted 7.2.0-rc4+
RIP: 0010:initialize_timer.constprop.0+0x20a/0x2d0
snd_seq_timer_start+0x15e/0x2b0
snd_seq_control_queue+0x56f/0xba0
snd_seq_write+0x3e0/0x730
Reject an overflowing product with check_mul_overflow() and fall back to
a single tick, which also avoids feeding a wrapped-but-nonzero divisor
(e.g. 2^63 * 1000 mod 2^64 == 0, or other resolutions wrapping to a small
value) into the period computation.
Fixes: 37745918e0 ("ALSA: timer: Introduce virtual userspace-driven timers")
Cc: <stable@vger.kernel.org>
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Norbert Szetei <norbert@doyensec.com>
Link: https://patch.msgid.link/DF8A3844-AD5E-4B8A-9CFC-BD83C212BA38@doyensec.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
The Razer Barracuda X 2.4 GHz USB headset dongle (0x1532:0x0552)
reports a minimum volume register value of cval->min = -16800.
In UAC 1/256 dB units, -16800 corresponds to -65.625 dB. However,
stock ALSA misinterprets this raw integer as 1/100 dB units
(-168.00 dB), causing user-space audio servers (PipeWire /
PulseAudio) to map their volume curves against an incorrectly wide
range.
Add an explicit usbmix_dB_map entry overriding Unit 2 to -6562
(-65.62 dB) to accurately report the physical hardware
attenuation bounds.
Signed-off-by: Markus Lindner <lindner.markus@outlook.at>
Link: https://patch.msgid.link/AS8P195MB2142F4EFF83980BD02BA6566E1C12@AS8P195MB2142.EURP195.PROD.OUTLOOK.COM
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Setting up the interface when suspended/resuming fails on this card.
Adding a reset and delay quirk will eliminate this problem.
usb 1-1: New USB device found, idVendor=0124, idProduct=0c21
usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 1-1: Product: USB Headphone
usb 1-1: Manufacturer: Generic
usb 1-1: SerialNumber: 20210726905926
Signed-off-by: Lianqin Hu <hulianqin@vivo.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/TYUPR06MB6217CBB68C8F868C076A4353D2C12@TYUPR06MB6217.apcprd06.prod.outlook.com
Convert atmel_ac97c_probe() to the managed APIs. Replace the open-coded
platform_get_resource() + ioremap() with devm_platform_ioremap_resource(),
which requests and maps the AC97C register window in one call. Switch the
clock to devm_clk_get_enabled(), the card to snd_devm_card_new(), and the
interrupt to devm_request_irq(). The now-unnecessary error-path cleanup
and the manual teardown in atmel_ac97c_remove() are dropped, since devm
handles them.
platform_get_irq() was already used; tighten its error check to irq < 0.
Both resource and IRQ lookups are equivalent for a platform-backed
device. The AC97C register window is owned solely by this driver, so the
new region request cannot conflict with another claimant, and it is
mapped exactly once (no double mapping).
No functional change; built for ARM (allmodconfig + SND_ATMEL_AC97C)
with LLVM=1 and sound/atmel/ac97c.o compiles cleanly.
Assisted-by: opencode:hy3-free
Signed-off-by: Rosen Penev <rosenp@gmail.com>
Link: https://patch.msgid.link/20260721225411.815553-1-rosenp@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Add aw88399_dev_set_channel() to the shared library so that the HDA side
codec driver can set the amplifier's channel assignment without
including the aw88395 device header directly.
The AW88399's struct aw_device is defined in aw88395_device.h, which
lives under sound/soc/codecs/aw88395/. Without this accessor, the
HDA driver would need a cross-subsystem relative include path to
access the channel field. Providing a setter in the library keeps the
interface clean and avoids coupling the HDA driver to ASoC-internal
headers.
Tested-by: Nadim Kobeissi <nadim@symbolic.software>
Tested-by: Xia Yun'an <imitoy@imitoy.top>
Tested-by: Munzir Taha <munzirtaha@gmail.com>
Signed-off-by: Marco Giunta <marco_giunta@outlook.it>
Link: https://patch.msgid.link/DS7PR19MB7724E8A1AD36D1E623FA2A0AFCC62@DS7PR19MB7724.namprd19.prod.outlook.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Add a fw_needs_reload flag to struct aw88399 that, when set, causes
aw88399_start to perform a full DSP firmware upload instead of
assuming the firmware binary is already present in memory.
After system sleep, the AW88399 loses its memory contents. The
existing start sequence assumes the firmware binary persists from
initialization and only uploads register configuration and DSP
config (AW88399_DSP_FW_UPDATE_OFF). When memory is empty, this causes
the subsequent CRC check to fail, triggering the retry mechanism in
aw88399_start_pa which re-uploads the firmware on the second
attempt.
While the retry mechanism recovers correctly, it produces
misleading error-level log messages on every resume cycle. The
fw_needs_reload flag allows the HDA side codec driver to signal
that a full firmware reload is needed after resume, eliminating
the spurious CRC failures.
The flag defaults to false via kzalloc, preserving the original
behavior for existing ASoC users. No existing code path sets this
flag; it will be set by the HDA side codec driver's system suspend
handler.
Tested-by: Nadim Kobeissi <nadim@symbolic.software>
Tested-by: Xia Yun'an <imitoy@imitoy.top>
Tested-by: Munzir Taha <munzirtaha@gmail.com>
Signed-off-by: Marco Giunta <marco_giunta@outlook.it>
Link: https://patch.msgid.link/DS7PR19MB77240CB79188C0B7AE243829FCC62@DS7PR19MB7724.namprd19.prod.outlook.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Add a bsts_unreliable flag to struct aw88399 that, when set, causes
the startup status check (aw_dev_check_sysst) to skip the BSTS
(boost startup finished) requirement.
On some hardware, the BSTS bit in the SYSST register (0x01, bit 9)
does not reliably assert even during normal audio playback. Register
inspection on affected Lenovo Legion hardware shows both amplifiers
reporting BSTS=0 on both channels despite clean audio output.
Per the AW88399 datasheet, BSTS indicates boost startup completion.
If BSTS never reliably sets to 1, the chip is never allowed to start
by aw_dev_check_sysst, regardless of whether the boot failure is genuine.
The new flag defaults to false via kzalloc, preserving the original check
behavior for all existing users. No existing code path sets this flag;
it will be set by the forthcoming HDA side codec property driver for
affected hardware.
Tested-by: Nadim Kobeissi <nadim@symbolic.software>
Tested-by: Xia Yun'an <imitoy@imitoy.top>
Tested-by: Munzir Taha <munzirtaha@gmail.com>
Signed-off-by: Marco Giunta <marco_giunta@outlook.it>
Link: https://patch.msgid.link/DS7PR19MB77242B8E5BB8BFB5E69816E9FCC62@DS7PR19MB7724.namprd19.prod.outlook.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Extend aw88399_parse_channel_dt to derive the audio channel from the
I2C address when the Device Tree property "awinic,audio-channel" is
absent.
The original code calls of_property_read_u32 without checking the
return value. On ACPI systems, the DT property is never present,
and channel_value is used uninitialized in the assignment to
aw_dev->channel.
Add a fallback that computes the channel as (i2c_addr - 0x34), where
0x34 is the AW88399's base I2C address per the datasheet (valid range
0x34-0x37). This channel assignment may be subsequently overridden by
the HDA side codec's property driver on systems that require it.
No change on Device Tree systems where the property is present.
Tested-by: Nadim Kobeissi <nadim@symbolic.software>
Tested-by: Xia Yun'an <imitoy@imitoy.top>
Tested-by: Munzir Taha <munzirtaha@gmail.com>
Co-developed-by: Yakov Till <yakov.till@gmail.com>
Signed-off-by: Yakov Till <yakov.till@gmail.com>
Signed-off-by: Marco Giunta <marco_giunta@outlook.it>
Link: https://patch.msgid.link/DS7PR19MB772468BB9F4D6925DC4E8E3EFCC62@DS7PR19MB7724.namprd19.prod.outlook.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Extract the device-level functions from aw88399.c into a new shared
library module (aw88399-lib.c) with a shared header at
include/sound/aw88399.h, following the pattern established by CS35L41
(cs35l41-lib.c / include/sound/cs35l41.h) for chips that need both
ASoC and HDA drivers.
The shared header at include/sound/aw88399.h contains the register
definitions, bit-field masks, hardware constants, device enums, the
struct aw88399 definition, and the library function declarations.
The ASoC-private header at sound/soc/codecs/aw88399.h is reduced to
ASoC-specific definitions (PCM formats/rates, ALSA kcontrol helpers,
calibration constants) and includes the shared header.
The library contains the chip initialization, firmware loading,
playback start/stop sequences, and all their internal dependencies
(PLL checks, DSP management, volume control, calibration, CRC
verification, etc.). The ASoC codec driver retains the ALSA controls,
DAPM widgets, codec probe/remove, calibration service, and I2C bus
driver registration.
A new Kconfig symbol SND_SOC_AW88399_LIB is introduced.
SND_SOC_AW88399 (the existing ASoC codec) selects it, ensuring no
change for current users. The HDA side codec driver (introduced
later in this series) selects the library without pulling in the
full ASoC codec module. This avoids a build-time dependency on the
full ASoC driver and follows the established pattern used by CS35L41
(SND_SOC_CS35L41_LIB) for chips with both ASoC and HDA drivers.
Some library functions (DSP control, volume setting, mute,
calibration updates, profile management, and status helpers) are
used internally by the library's start/stop sequences but are also
called directly by the ASoC driver's remaining code.
These are exported from the library so the ASoC module can access them.
This is a pure code movement with no functional changes. The moved
functions are identical to their originals in aw88399.c.
Tested-by: Nadim Kobeissi <nadim@symbolic.software>
Tested-by: Xia Yun'an <imitoy@imitoy.top>
Tested-by: Munzir Taha <munzirtaha@gmail.com>
Signed-off-by: Marco Giunta <marco_giunta@outlook.it>
Link: https://patch.msgid.link/DS7PR19MB772415C485FAF74297673FD7FCC62@DS7PR19MB7724.namprd19.prod.outlook.com
Signed-off-by: Mark Brown <broonie@kernel.org>
When userspace writes 1 to /sys/bus/pci/devices/XX/remove to remove
HDA PCI device, the HDA hardware control path is shut down and devres
unmaps the BAR virtual address bus->remap_addr automatically during
driver removal.
If a delayed HDA verb command arrives after the MMIO region is
unmapped, the driver will access invalid virtual addresses and trigger
a page fault splat.
So add an error check right after constructing snd_hda_power_pm.
Signed-off-by: Bob Song <songxiebing@kylinos.cn>
Link: https://patch.msgid.link/20260717024948.506335-1-songxiebing@kylinos.cn
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Add timer_shutdown_sync() call at the free callback for systimer
backend, in order to make sure that we can release the resources.
This is only for hardening, and there shouldn't be any actual issue
that requires this change for now.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/20260720135356.1779857-4-tiwai@suse.de
The systimer backend invokes timer_delete() at stopping the PCM, but
it misses its synchronization, which might lead to concurrent changes
or releases at PCM prepare or free. Use the sync_stop callback to
assure the synchronization of timer deletion.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/20260720135356.1779857-3-tiwai@suse.de
The hrtimer backend code in ALSA dummy driver calls explicitly the
synchronization of hrtimer cancel from prepare and free callbacks, and
this is exactly what the standard PCM sync_stop callback serves for.
Replace the open-code with the standard PCM sync_stop callback.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/20260720135356.1779857-2-tiwai@suse.de
tas2563_save_calibration() assigns cali_data.total_sz before it reads the
per-device calibration data from EFI, but its error paths return without
clearing it again. cali_data.cali_reg_array is left all zero, because the
function returns before the register addresses are assigned.
On the first playback tasdev_load_calibrated_data() does
if (!data || !cali_data->total_sz)
return;
which passes, since total_sz is still non-zero. It then issues five
4-byte bulk writes to p->r0_reg, p->r0_low_reg, p->invr0_reg, p->pow_reg
and p->tlimit_reg, all of which are 0. Register 0 decodes to book 0 /
page 0 / register 0x00, so the auto-incrementing block write zeroes
registers 0x00 to 0x03. Register 0x03 is PB_CFG1, which holds AMP_LEVEL,
so the amplifier gain is set to its minimum and the speaker stays silent.
This is reproducible on a Lenovo Yoga 7 14ARB7 (two TAS2563 on I2C,
ACPI INT8866) whose factory calibration was never written to UEFI, so the
EFI read fails with EFI_NOT_FOUND. The two woofers driven by the
amplifiers are silent while the tweeters driven directly by the ALC287
play. Reading the amplifier registers over i2c shows PWR_CTL = 0x00
(active) and the TDM slots correctly programmed by the RCA profile, but
PB_CFG1 = 0x00. With this change PB_CFG1 keeps its power-on default of
0x20 and both woofers play.
tas2781_save_calibration() in tas2781_hda.c already clears total_sz on
failure; do the same for the TAS2563 variant.
Signed-off-by: Philipp Oster <philippdev5396@outlook.de>
Link: https://patch.msgid.link/20260720-tas2781-calfix-v1-1-3a5fa6ad90bc@outlook.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
The firmware on the Lunnen Ground 14 marks pin 0x1b as unused even
though the internal speakers are connected to it. As a result, the
speakers are not detected.
Add a pin configuration quirk for PCI subsystem ID 2782:a212 to configure
pin 0x1b as an internal speaker.
The pin configuration was tested on a Lunnen Ground 14 (DMI product LL4FA)
with an ALC269VC codec. The internal speakers and microphone work as
expected.
Cc: stable@vger.kernel.org
Signed-off-by: Nikita Maksimov <nickstogramm@yandex.ru>
Link: https://patch.msgid.link/20260720180214.73770-1-nickstogramm@yandex.ru
Signed-off-by: Takashi Iwai <tiwai@suse.de>
snd_timer_close_locked() drains the closing instance's own in-flight
callback (IFLG_CALLBACK) before freeing it, but not its slaves'. When a
master instance is closed, remove_slave_links() clears each slave's
->timer; the slave's own close then reads timer == NULL and takes the
branch that skips the drain entirely (snd_timer_stop_slave() also no-ops
on a NULL timer). So a slave whose callback is still running when the
master is closed is freed underneath the live callback, leading to
use-after-free.
Drain the slaves too before remove_slave_links() severs them.
snd_timer_stop() has already taken this instance off the active list, so
no new slave callback can be queued. Take the slaves off the ack list so
a pending one can't fire either, then wait for any that is already in
flight.
Fixes: 37745918e0 ("ALSA: timer: Introduce virtual userspace-driven timers")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Norbert Szetei <norbert@doyensec.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/D26598EB-DBF7-4D76-9F71-8E4BD59822D4@doyensec.com
The userspace-driven timer (utimer) TRIGGER ioctl calls
snd_timer_interrupt() directly with no serialization, so two threads
triggering the same utimer can run snd_timer_interrupt() on one
snd_timer concurrently.
snd_timer_process_callbacks() drops timer->lock around each instance
callback and marks the in-flight callback with the single
SNDRV_TIMER_IFLG_CALLBACK bit; snd_timer_close_locked() waits on that
bit to drain an in-flight callback before freeing the instance. The bit
cannot represent two concurrent callbacks: when a second interrupt
re-queues an instance whose callback is still running, both run at once,
the first to finish clears the bit, and the close-path drain then frees
the instance (and its callback_data) while the other callback is still
live - a use-after-free reachable by any user able to open
/dev/snd/timer, both via a user timer instance and via a sequencer queue
timer bound to the utimer.
snd_timer_interrupt() sets IFLG_CALLBACK before dropping timer->lock, so
a concurrent interrupt already observes it under the lock. Skip
re-queuing an instance (and its slaves) to the ack/sack list while its
callback is in flight; the accumulated pticks are delivered on the next
tick, so no event is lost.
Fixes: 37745918e0 ("ALSA: timer: Introduce virtual userspace-driven timers")
Cc: stable@vger.kernel.org
Suggested-by: Takashi Iwai <tiwai@suse.de>
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Norbert Szetei <norbert@doyensec.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/6F9B6501-8E65-4265-B02C-7EFB240D1664@doyensec.com