git: cbd730ebeb03 - stable/15 - snd_emu10kx: Make sure the block count and size cover the whole buffer
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 14 Sep 2026 10:45:08 UTC
The branch stable/15 has been updated by christos:
URL: https://cgit.FreeBSD.org/src/commit/?id=cbd730ebeb03e26578bdef61669acca1cc7c65fa
commit cbd730ebeb03e26578bdef61669acca1cc7c65fa
Author: Christos Margiolis <christos@FreeBSD.org>
AuthorDate: 2026-09-07 14:48:21 +0000
Commit: Christos Margiolis <christos@FreeBSD.org>
CommitDate: 2026-09-14 10:44:57 +0000
snd_emu10kx: Make sure the block count and size cover the whole buffer
The playback voices always loop over the whole EMU_PLAY_BUFSZ buffer,
but emupchan_setblocksize() only recorded the new block size and left
the block count as it was set up by emu_vinit(). The blocks then no
longer covered the whole buffer, and the part they left out was played
without ever being written to, which became audible as distortion once
playback started going through a virtual channel.
Resize the buffer, so that the block count and size always cover it.
Fixes: 02d4eeabfd73 ("sound: Allocate vchans on-demand")
PR: 287687
MFC after: 1 week
Sponsored by: The FreeBSD Foundation
Reviewed by: markj
Differential Revision: https://reviews.freebsd.org/D59444
(cherry picked from commit a7258157e1a20957af23332814197ea723f5778d)
---
sys/dev/sound/pci/emu10kx-pcm.c | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/sys/dev/sound/pci/emu10kx-pcm.c b/sys/dev/sound/pci/emu10kx-pcm.c
index 7cb371d82d39..0a15b8ba3448 100644
--- a/sys/dev/sound/pci/emu10kx-pcm.c
+++ b/sys/dev/sound/pci/emu10kx-pcm.c
@@ -768,13 +768,30 @@ emupchan_setblocksize(kobj_t obj __unused, void *c_devinfo, uint32_t blocksize)
{
struct emu_pcm_pchinfo *ch = c_devinfo;
struct emu_pcm_info *sc = ch->pcm;
+ uint32_t blkcnt;
+
+ /*
+ * The channel always plays the whole EMU_PLAY_BUFSZ buffer, so the
+ * blocks have to cover it exactly, or the part they do not cover is
+ * "played" without ever being written to.
+ *
+ * sndbuf_resize() needs at least two blocks, so a block can be at most
+ * half the buffer's size. The block count has to be a power of two as
+ * well, because only then does the division come out exact.
+ */
+ if (blocksize == 0 || blocksize > EMU_PLAY_BUFSZ / 2)
+ blocksize = EMU_PLAY_BUFSZ / 2;
+ blkcnt = 1 << (fls(EMU_PLAY_BUFSZ / blocksize) - 1);
+ blocksize = EMU_PLAY_BUFSZ / blkcnt;
+
+ if (sndbuf_resize(ch->buffer, blkcnt, blocksize) != 0)
+ return (ch->blksz);
- if (blocksize > ch->pcm->bufsz)
- blocksize = ch->pcm->bufsz;
mtx_lock(&sc->lock);
ch->blksz = blocksize;
emu_timer_set(sc->card, ch->timer, ch->blksz / ch->buffer->align);
mtx_unlock(&sc->lock);
+
return (ch->blksz);
}