mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 11:25:21 +01:00
sound: Check for errors from sndbuf_resize()
Most implementations of CHANNEL_SETBLOCKSIZE and CHANNEL_SETFRAGMENTS were not checking this. This is probably not a big problem: it's unlikely for sndbuf_resize() to fail due to the refcount check in this case since it's operating on the hardware buffer, which doesn't get mmaped. But, I will add more reasons for it to fail in the next patch, so let's be more careful. This change modifies various CHANNEL_SETBLOCKSIZE implementations to check for errors. In some cases I reordered things to avoid updating driver state until after sndbuf_resize() succeeds. Return 0 from CHANNEL_SETBLOCKSIZE to indicate an error, as it otherwise returns the new block size. We could change the interface to return both an error number and a block size, but that would break at least one out-of-tree driver and I wish to avoid that here. Make sure that errors from CHANNEL_SETFRAGMENTS and CHANNEL_SETBLOCKSIZE are returned to userspace. Approved by: so Security: FreeBSD-SA-26:71.sound Reviewed by: christos Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D60553
This commit is contained in:
1 parent
9a406a9ec3
commit
3545fc68f4
23 files changed
+124
-82
No files matched your search
@@ -394,7 +394,8 @@ ssichan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
|
||||
struct sc_pcminfo *scp = ch->parent;
|
||||
struct sc_info *sc = scp->sc;
|
||||
|
||||
sndbuf_resize(ch->buffer, sc->dma_size / blocksize, blocksize);
|
||||
if (sndbuf_resize(ch->buffer, sc->dma_size / blocksize, blocksize) != 0)
|
||||
return (0);
|
||||
|
||||
setup_dma(scp);
|
||||
|
||||
|
||||
@@ -367,7 +367,8 @@ saichan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
|
||||
struct sc_pcminfo *scp = ch->parent;
|
||||
struct sc_info *sc = scp->sc;
|
||||
|
||||
sndbuf_resize(ch->buffer, sc->dma_size / blocksize, blocksize);
|
||||
if (sndbuf_resize(ch->buffer, sc->dma_size / blocksize, blocksize) != 0)
|
||||
return (0);
|
||||
|
||||
sc->period = ch->buffer->blksz;
|
||||
return (sc->period);
|
||||
|
||||
@@ -113,7 +113,8 @@ fwisound_chan_setblocksize(kobj_t obj, void *data, uint32_t blksz)
|
||||
if (blksz < 4)
|
||||
blksz = 4;
|
||||
|
||||
sndbuf_resize(chan->buf, chan->buf->bufsize / blksz, blksz);
|
||||
if (sndbuf_resize(chan->buf, chan->buf->bufsize / blksz, blksz) != 0)
|
||||
return (0);
|
||||
|
||||
return (chan->buf->blksz);
|
||||
}
|
||||
|
||||
@@ -267,7 +267,8 @@ alschan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
|
||||
if (blocksize > sc->bufsz / 2) {
|
||||
blocksize = sc->bufsz / 2;
|
||||
}
|
||||
sndbuf_resize(ch->buffer, 2, blocksize);
|
||||
if (sndbuf_resize(ch->buffer, 2, blocksize) != 0)
|
||||
return 0;
|
||||
return blocksize;
|
||||
}
|
||||
|
||||
|
||||
@@ -532,6 +532,7 @@ atiixp_chan_setfragments(kobj_t obj, void *data,
|
||||
{
|
||||
struct atiixp_chinfo *ch = data;
|
||||
struct atiixp_info *sc = ch->parent;
|
||||
int error;
|
||||
|
||||
blksz &= ATI_IXP_BLK_ALIGN;
|
||||
|
||||
@@ -555,9 +556,11 @@ atiixp_chan_setfragments(kobj_t obj, void *data,
|
||||
|
||||
if ((ch->buffer->blksz != blksz ||
|
||||
ch->buffer->blkcnt != blkcnt) &&
|
||||
sndbuf_resize(ch->buffer, blkcnt, blksz) != 0)
|
||||
(error = sndbuf_resize(ch->buffer, blkcnt, blksz)) != 0) {
|
||||
device_printf(sc->dev, "%s: failed blksz=%u blkcnt=%u\n",
|
||||
__func__, blksz, blkcnt);
|
||||
return (error);
|
||||
}
|
||||
|
||||
ch->blksz = ch->buffer->blksz;
|
||||
ch->blkcnt = ch->buffer->blkcnt;
|
||||
@@ -571,7 +574,8 @@ atiixp_chan_setblocksize(kobj_t obj, void *data, uint32_t blksz)
|
||||
struct atiixp_chinfo *ch = data;
|
||||
struct atiixp_info *sc = ch->parent;
|
||||
|
||||
atiixp_chan_setfragments(obj, data, blksz, sc->blkcnt);
|
||||
if (atiixp_chan_setfragments(obj, data, blksz, sc->blkcnt) != 0)
|
||||
return (0);
|
||||
|
||||
return (ch->blksz);
|
||||
}
|
||||
|
||||
@@ -470,7 +470,8 @@ cmichan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
|
||||
if (blocksize > sc->bufsz / CMI_INTR_PER_BUFFER) {
|
||||
blocksize = sc->bufsz / CMI_INTR_PER_BUFFER;
|
||||
}
|
||||
sndbuf_resize(ch->buffer, CMI_INTR_PER_BUFFER, blocksize);
|
||||
if (sndbuf_resize(ch->buffer, CMI_INTR_PER_BUFFER, blocksize) != 0)
|
||||
return 0;
|
||||
|
||||
return blocksize;
|
||||
}
|
||||
|
||||
@@ -346,12 +346,14 @@ cs4281chan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
|
||||
struct sc_info *sc = ch->parent;
|
||||
uint32_t go;
|
||||
|
||||
go = adcdac_go(ch, 0);
|
||||
|
||||
/* 2 interrupts are possible and used in buffer (half-empty,empty),
|
||||
* hence factor of 2. */
|
||||
ch->blksz = min(blocksize, sc->bufsz / 2);
|
||||
sndbuf_resize(ch->buffer, 2, ch->blksz);
|
||||
blocksize = min(blocksize, sc->bufsz / 2);
|
||||
if (sndbuf_resize(ch->buffer, 2, blocksize) != 0)
|
||||
return 0;
|
||||
ch->blksz = blocksize;
|
||||
|
||||
go = adcdac_go(ch, 0);
|
||||
ch->dma_setup = 0;
|
||||
adcdac_prog(ch);
|
||||
adcdac_go(ch, go);
|
||||
|
||||
@@ -785,7 +785,7 @@ emupchan_setblocksize(kobj_t obj __unused, void *c_devinfo, uint32_t blocksize)
|
||||
blocksize = EMU_PLAY_BUFSZ / blkcnt;
|
||||
|
||||
if (sndbuf_resize(ch->buffer, blkcnt, blocksize) != 0)
|
||||
return (ch->blksz);
|
||||
return (0);
|
||||
|
||||
mtx_lock(&sc->lock);
|
||||
ch->blksz = blocksize;
|
||||
|
||||
@@ -1714,7 +1714,7 @@ envy24chan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
|
||||
{
|
||||
struct sc_chinfo *ch = data;
|
||||
/* struct sc_info *sc = ch->parent; */
|
||||
uint32_t size, prev;
|
||||
uint32_t blk, size, prev;
|
||||
unsigned int bcnt, bsize;
|
||||
|
||||
#if(0)
|
||||
@@ -1729,20 +1729,22 @@ envy24chan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
|
||||
break;
|
||||
}
|
||||
|
||||
ch->blk = prev / ch->unit;
|
||||
blk = prev / ch->unit;
|
||||
if (ch->dir == PCMDIR_PLAY)
|
||||
ch->blk *= ENVY24_PLAY_BUFUNIT / 4;
|
||||
blk *= ENVY24_PLAY_BUFUNIT / 4;
|
||||
else
|
||||
ch->blk *= ENVY24_REC_BUFUNIT / 4;
|
||||
blk *= ENVY24_REC_BUFUNIT / 4;
|
||||
/* set channel buffer information */
|
||||
/* ch->size = ch->unit * ENVY24_SAMPLE_NUM; */
|
||||
if (ch->dir == PCMDIR_PLAY)
|
||||
bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT;
|
||||
bsize = blk * 4 / ENVY24_PLAY_BUFUNIT;
|
||||
else
|
||||
bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT;
|
||||
bsize = blk * 4 / ENVY24_REC_BUFUNIT;
|
||||
bsize *= ch->unit;
|
||||
bcnt = ch->size / bsize;
|
||||
sndbuf_resize(ch->buffer, bcnt, bsize);
|
||||
if (sndbuf_resize(ch->buffer, bcnt, bsize) != 0)
|
||||
return 0;
|
||||
ch->blk = blk;
|
||||
/* mtx_unlock(&sc->lock); */
|
||||
|
||||
#if(0)
|
||||
|
||||
@@ -1625,7 +1625,7 @@ envy24htchan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
|
||||
{
|
||||
struct sc_chinfo *ch = data;
|
||||
/* struct sc_info *sc = ch->parent; */
|
||||
uint32_t size, prev;
|
||||
uint32_t blk, size, prev;
|
||||
unsigned int bcnt, bsize;
|
||||
|
||||
#if(0)
|
||||
@@ -1640,20 +1640,22 @@ envy24htchan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
|
||||
break;
|
||||
}
|
||||
|
||||
ch->blk = prev / ch->unit;
|
||||
blk = prev / ch->unit;
|
||||
if (ch->dir == PCMDIR_PLAY)
|
||||
ch->blk *= ENVY24HT_PLAY_BUFUNIT / 4;
|
||||
blk *= ENVY24HT_PLAY_BUFUNIT / 4;
|
||||
else
|
||||
ch->blk *= ENVY24HT_REC_BUFUNIT / 4;
|
||||
blk *= ENVY24HT_REC_BUFUNIT / 4;
|
||||
/* set channel buffer information */
|
||||
/* ch->size = ch->unit * ENVY24HT_SAMPLE_NUM; */
|
||||
if (ch->dir == PCMDIR_PLAY)
|
||||
bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
|
||||
bsize = blk * 4 / ENVY24HT_PLAY_BUFUNIT;
|
||||
else
|
||||
bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
|
||||
bsize = blk * 4 / ENVY24HT_REC_BUFUNIT;
|
||||
bsize *= ch->unit;
|
||||
bcnt = ch->size / bsize;
|
||||
sndbuf_resize(ch->buffer, bcnt, bsize);
|
||||
if (sndbuf_resize(ch->buffer, bcnt, bsize) != 0)
|
||||
return 0;
|
||||
ch->blk = blk;
|
||||
/* mtx_unlock(&sc->lock); */
|
||||
|
||||
#if(0)
|
||||
|
||||
@@ -634,6 +634,7 @@ eschan_setfragments(kobj_t obj, void *data, uint32_t blksz, uint32_t blkcnt)
|
||||
{
|
||||
struct es_chinfo *ch = data;
|
||||
struct es_info *es = ch->parent;
|
||||
int error;
|
||||
|
||||
blksz &= ES_BLK_ALIGN;
|
||||
|
||||
@@ -657,9 +658,11 @@ eschan_setfragments(kobj_t obj, void *data, uint32_t blksz, uint32_t blkcnt)
|
||||
|
||||
if ((ch->buffer->blksz != blksz ||
|
||||
ch->buffer->blkcnt != blkcnt) &&
|
||||
sndbuf_resize(ch->buffer, blkcnt, blksz) != 0)
|
||||
(error = sndbuf_resize(ch->buffer, blkcnt, blksz)) != 0) {
|
||||
device_printf(es->dev, "%s: failed blksz=%u blkcnt=%u\n",
|
||||
__func__, blksz, blkcnt);
|
||||
return (error);
|
||||
}
|
||||
|
||||
ch->bufsz = ch->buffer->bufsize;
|
||||
ch->blksz = ch->buffer->blksz;
|
||||
@@ -674,7 +677,8 @@ eschan_setblocksize(kobj_t obj, void *data, uint32_t blksz)
|
||||
struct es_chinfo *ch = data;
|
||||
struct es_info *es = ch->parent;
|
||||
|
||||
eschan_setfragments(obj, data, blksz, es->blkcnt);
|
||||
if (eschan_setfragments(obj, data, blksz, es->blkcnt) != 0)
|
||||
return (0);
|
||||
|
||||
return (ch->blksz);
|
||||
}
|
||||
|
||||
@@ -2080,6 +2080,7 @@ hdaa_channel_setfragments(kobj_t obj, void *data,
|
||||
uint32_t blksz, uint32_t blkcnt)
|
||||
{
|
||||
struct hdaa_chan *ch = data;
|
||||
int error;
|
||||
|
||||
blksz -= blksz % lcm(HDA_DMA_ALIGNMENT, ch->b->align);
|
||||
|
||||
@@ -2101,11 +2102,12 @@ hdaa_channel_setfragments(kobj_t obj, void *data,
|
||||
break;
|
||||
}
|
||||
|
||||
if ((ch->b->blksz != blksz ||
|
||||
ch->b->blkcnt != blkcnt) &&
|
||||
sndbuf_resize(ch->b, blkcnt, blksz) != 0)
|
||||
if ((ch->b->blksz != blksz || ch->b->blkcnt != blkcnt) &&
|
||||
(error = sndbuf_resize(ch->b, blkcnt, blksz)) != 0) {
|
||||
device_printf(ch->devinfo->dev, "%s: failed blksz=%u blkcnt=%u\n",
|
||||
__func__, blksz, blkcnt);
|
||||
return (error);
|
||||
}
|
||||
|
||||
ch->blksz = ch->b->blksz;
|
||||
ch->blkcnt = ch->b->blkcnt;
|
||||
@@ -2118,7 +2120,9 @@ hdaa_channel_setblocksize(kobj_t obj, void *data, uint32_t blksz)
|
||||
{
|
||||
struct hdaa_chan *ch = data;
|
||||
|
||||
hdaa_channel_setfragments(obj, data, blksz, ch->pdevinfo->chan_blkcnt);
|
||||
if (hdaa_channel_setfragments(obj, data, blksz,
|
||||
ch->pdevinfo->chan_blkcnt) != 0)
|
||||
return (0);
|
||||
|
||||
return (ch->blksz);
|
||||
}
|
||||
|
||||
@@ -943,6 +943,10 @@ hdspchan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
|
||||
}
|
||||
}
|
||||
|
||||
if (sndbuf_resize(ch->buffer, 2,
|
||||
(hl->period * AFMT_CHANNEL(ch->format) * sizeof(uint32_t))) != 0)
|
||||
return (0);
|
||||
|
||||
mtx_lock(&sc->lock);
|
||||
sc->ctrl_register &= ~HDSP_LAT_MASK;
|
||||
sc->ctrl_register |= hdsp_encode_latency(hl->n);
|
||||
@@ -954,9 +958,6 @@ hdspchan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
|
||||
device_printf(scp->dev, "New period=%d\n", sc->period);
|
||||
#endif
|
||||
|
||||
sndbuf_resize(ch->buffer, 2,
|
||||
(sc->period * AFMT_CHANNEL(ch->format) * sizeof(uint32_t)));
|
||||
|
||||
/* Reset pointer, rewrite frequency (same register) for 9632. */
|
||||
hdsp_write_4(sc, HDSP_RESET_POINTER, 0);
|
||||
if (sc->type == HDSP_9632)
|
||||
|
||||
@@ -941,6 +941,11 @@ hdspechan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
|
||||
}
|
||||
}
|
||||
|
||||
if (sndbuf_resize(ch->buffer,
|
||||
(HDSPE_CHANBUF_SIZE * AFMT_CHANNEL(ch->format)) / (hl->period * 4),
|
||||
(hl->period * 4)) != 0)
|
||||
return (0);
|
||||
|
||||
mtx_lock(&sc->lock);
|
||||
sc->ctrl_register &= ~HDSPE_LAT_MASK;
|
||||
sc->ctrl_register |= hdspe_encode_latency(hl->n);
|
||||
@@ -952,9 +957,6 @@ hdspechan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
|
||||
device_printf(scp->dev, "New period=%d\n", sc->period);
|
||||
#endif
|
||||
|
||||
sndbuf_resize(ch->buffer,
|
||||
(HDSPE_CHANBUF_SIZE * AFMT_CHANNEL(ch->format)) / (sc->period * 4),
|
||||
(sc->period * 4));
|
||||
end:
|
||||
|
||||
return (ch->buffer->blksz);
|
||||
|
||||
+13
-10
@@ -294,21 +294,23 @@ AC97_DECLARE(ich_ac97);
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* common routines */
|
||||
|
||||
static void
|
||||
ich_filldtbl(struct sc_chinfo *ch)
|
||||
static int
|
||||
ich_filldtbl(struct sc_chinfo *ch, uint32_t blksz)
|
||||
{
|
||||
struct sc_info *sc = ch->parent;
|
||||
uint32_t base;
|
||||
int i;
|
||||
int error, i;
|
||||
|
||||
base = ch->buffer->buf_addr;
|
||||
if ((ch->blksz * ch->blkcnt) > ch->buffer->maxsize)
|
||||
ch->blksz = ch->buffer->maxsize / ch->blkcnt;
|
||||
if ((ch->buffer->blksz != ch->blksz ||
|
||||
if (blksz * ch->blkcnt > ch->buffer->maxsize)
|
||||
blksz = ch->buffer->maxsize / ch->blkcnt;
|
||||
if ((ch->buffer->blksz != blksz ||
|
||||
ch->buffer->blkcnt != ch->blkcnt) &&
|
||||
sndbuf_resize(ch->buffer, ch->blkcnt, ch->blksz) != 0)
|
||||
(error = sndbuf_resize(ch->buffer, ch->blkcnt, blksz)) != 0) {
|
||||
device_printf(sc->dev, "%s: failed blksz=%u blkcnt=%u\n",
|
||||
__func__, ch->blksz, ch->blkcnt);
|
||||
__func__, blksz, ch->blkcnt);
|
||||
return (error);
|
||||
}
|
||||
ch->blksz = ch->buffer->blksz;
|
||||
|
||||
for (i = 0; i < ICH_DTBL_LENGTH; i++) {
|
||||
@@ -316,6 +318,7 @@ ich_filldtbl(struct sc_chinfo *ch)
|
||||
ch->dtbl[i].length = ICH_BDC_IOC
|
||||
| (ch->blksz / ch->parent->sample_size);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -496,8 +499,8 @@ ichchan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
|
||||
if (blocksize < ICH_MIN_BLKSZ)
|
||||
blocksize = ICH_MIN_BLKSZ;
|
||||
blocksize &= ~(ICH_MIN_BLKSZ - 1);
|
||||
ch->blksz = blocksize;
|
||||
ich_filldtbl(ch);
|
||||
if (ich_filldtbl(ch, blocksize) != 0)
|
||||
return (0);
|
||||
ICH_LOCK(sc);
|
||||
ich_wr(sc, ch->regbase + ICH_REG_X_LVI, ch->blkcnt - 1, 1);
|
||||
ICH_UNLOCK(sc);
|
||||
|
||||
@@ -538,7 +538,8 @@ trpchan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
|
||||
{
|
||||
struct tr_chinfo *ch = data;
|
||||
|
||||
sndbuf_resize(ch->buffer, 2, blocksize);
|
||||
if (sndbuf_resize(ch->buffer, 2, blocksize) != 0)
|
||||
return 0;
|
||||
return blocksize;
|
||||
}
|
||||
|
||||
@@ -659,8 +660,8 @@ trrchan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
|
||||
{
|
||||
struct tr_rchinfo *ch = data;
|
||||
|
||||
sndbuf_resize(ch->buffer, 2, blocksize);
|
||||
|
||||
if (sndbuf_resize(ch->buffer, 2, blocksize) != 0)
|
||||
return 0;
|
||||
return blocksize;
|
||||
}
|
||||
|
||||
|
||||
@@ -565,6 +565,7 @@ via8233chan_setfragments(kobj_t obj, void *data,
|
||||
{
|
||||
struct via_chinfo *ch = data;
|
||||
struct via_info *via = ch->parent;
|
||||
int error;
|
||||
|
||||
blksz &= VIA_BLK_ALIGN;
|
||||
|
||||
@@ -588,9 +589,11 @@ via8233chan_setfragments(kobj_t obj, void *data,
|
||||
|
||||
if ((ch->buffer->blksz != blksz ||
|
||||
ch->buffer->blkcnt != blkcnt) &&
|
||||
sndbuf_resize(ch->buffer, blkcnt, blksz) != 0)
|
||||
(error = sndbuf_resize(ch->buffer, blkcnt, blksz)) != 0) {
|
||||
device_printf(via->dev, "%s: failed blksz=%u blkcnt=%u\n",
|
||||
__func__, blksz, blkcnt);
|
||||
return (error);
|
||||
}
|
||||
|
||||
ch->blksz = ch->buffer->blksz;
|
||||
ch->blkcnt = ch->buffer->blkcnt;
|
||||
@@ -604,7 +607,8 @@ via8233chan_setblocksize(kobj_t obj, void *data, uint32_t blksz)
|
||||
struct via_chinfo *ch = data;
|
||||
struct via_info *via = ch->parent;
|
||||
|
||||
via8233chan_setfragments(obj, data, blksz, via->blkcnt);
|
||||
if (via8233chan_setfragments(obj, data, blksz, via->blkcnt) != 0)
|
||||
return (0);
|
||||
|
||||
return (ch->blksz);
|
||||
}
|
||||
|
||||
@@ -328,8 +328,9 @@ viachan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
|
||||
{
|
||||
struct via_chinfo *ch = data;
|
||||
|
||||
if (sndbuf_resize(ch->buffer, SEGS_PER_CHAN, blocksize) != 0)
|
||||
return 0;
|
||||
ch->blksz = blocksize;
|
||||
sndbuf_resize(ch->buffer, SEGS_PER_CHAN, ch->blksz);
|
||||
|
||||
return ch->blksz;
|
||||
}
|
||||
|
||||
@@ -224,7 +224,8 @@ svchan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
|
||||
|
||||
/* user has requested interrupts every blocksize bytes */
|
||||
RANGE(blocksize, SV_MIN_BLKSZ, sc->bufsz / SV_INTR_PER_BUFFER);
|
||||
sndbuf_resize(ch->buffer, SV_INTR_PER_BUFFER, blocksize);
|
||||
if (sndbuf_resize(ch->buffer, SV_INTR_PER_BUFFER, blocksize) != 0)
|
||||
return 0;
|
||||
DEB(printf("svchan_setblocksize: %d\n", blocksize));
|
||||
return blocksize;
|
||||
}
|
||||
|
||||
@@ -1837,7 +1837,6 @@ chn_resizebuf(struct pcm_channel *c, int latency,
|
||||
{
|
||||
struct snd_dbuf *b, *bs, *pb;
|
||||
int sblksz, sblkcnt, hblksz, hblkcnt, limit = 0, nsblksz, nsblkcnt;
|
||||
int ret;
|
||||
u_int32_t maxsize;
|
||||
|
||||
CHN_LOCKASSERT(c);
|
||||
@@ -1909,6 +1908,8 @@ chn_resizebuf(struct pcm_channel *c, int latency,
|
||||
sndbuf_xbytes(pb->blksz, pb, bs) * 2 : 0;
|
||||
}
|
||||
} else {
|
||||
int error;
|
||||
|
||||
/*
|
||||
* The byte-rate-scaled cap applies to the secondary buffer
|
||||
* only. It exists to absorb userland scheduling latency,
|
||||
@@ -1942,11 +1943,27 @@ chn_resizebuf(struct pcm_channel *c, int latency,
|
||||
hblksz -= hblksz % b->align;
|
||||
|
||||
CHN_UNLOCK(c);
|
||||
if (chn_usefrags == 0 ||
|
||||
CHANNEL_SETFRAGMENTS(c->methods, c->devinfo,
|
||||
hblksz, hblkcnt) != 0)
|
||||
b->blksz = CHANNEL_SETBLOCKSIZE(c->methods,
|
||||
c->devinfo, hblksz);
|
||||
error = ENOTSUP;
|
||||
if (chn_usefrags) {
|
||||
error = CHANNEL_SETFRAGMENTS(c->methods, c->devinfo,
|
||||
hblksz, hblkcnt);
|
||||
/* The default implementation returns ENOTSUP. */
|
||||
if (error != 0 && error != ENOTSUP) {
|
||||
CHN_LOCK(c);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
if (error == ENOTSUP) {
|
||||
uint32_t nblksz;
|
||||
|
||||
nblksz = CHANNEL_SETBLOCKSIZE(c->methods, c->devinfo,
|
||||
hblksz);
|
||||
if (nblksz == 0) {
|
||||
CHN_LOCK(c);
|
||||
return EINVAL;
|
||||
}
|
||||
b->blksz = nblksz;
|
||||
}
|
||||
CHN_LOCK(c);
|
||||
|
||||
if (!CHN_EMPTY(c, children)) {
|
||||
@@ -1985,11 +2002,13 @@ chn_resizebuf(struct pcm_channel *c, int latency,
|
||||
|
||||
if (bs->blkcnt != sblkcnt || bs->blksz != sblksz ||
|
||||
bs->bufsize != (sblkcnt * sblksz)) {
|
||||
ret = sndbuf_remalloc(bs, sblkcnt, sblksz);
|
||||
if (ret != 0) {
|
||||
int error;
|
||||
|
||||
error = sndbuf_remalloc(bs, sblkcnt, sblksz);
|
||||
if (error != 0) {
|
||||
device_printf(c->dev, "%s(): Failed: %d %d\n",
|
||||
__func__, sblkcnt, sblksz);
|
||||
return ret;
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2792,16 +2792,12 @@ uaudio_chan_free(struct uaudio_chan *ch)
|
||||
int
|
||||
uaudio_chan_set_param_blocksize(struct uaudio_chan *ch, uint32_t blocksize)
|
||||
{
|
||||
uint32_t temp = 2 * uaudio_get_buffer_size(ch, ch->set_alt);
|
||||
sndbuf_setup(ch->pcm_buf, ch->buf, temp);
|
||||
return (temp / 2);
|
||||
}
|
||||
uint32_t temp;
|
||||
|
||||
int
|
||||
uaudio_chan_set_param_fragments(struct uaudio_chan *ch, uint32_t blocksize,
|
||||
uint32_t blockcount)
|
||||
{
|
||||
return (1);
|
||||
temp = 2 * uaudio_get_buffer_size(ch, ch->set_alt);
|
||||
if (sndbuf_setup(ch->pcm_buf, ch->buf, temp) != 0)
|
||||
return (0);
|
||||
return (temp / 2);
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
@@ -45,8 +45,6 @@ extern void *uaudio_chan_init(struct uaudio_chan *ch, struct snd_dbuf *b,
|
||||
extern int uaudio_chan_free(struct uaudio_chan *ch);
|
||||
extern int uaudio_chan_set_param_blocksize(struct uaudio_chan *ch,
|
||||
uint32_t blocksize);
|
||||
extern int uaudio_chan_set_param_fragments(struct uaudio_chan *ch,
|
||||
uint32_t blocksize, uint32_t blockcount);
|
||||
extern int uaudio_chan_set_param_speed(struct uaudio_chan *ch,
|
||||
uint32_t speed);
|
||||
extern int uaudio_chan_getptr(struct uaudio_chan *ch);
|
||||
|
||||
@@ -71,12 +71,6 @@ ua_chan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
|
||||
return (uaudio_chan_set_param_blocksize(data, blocksize));
|
||||
}
|
||||
|
||||
static int
|
||||
ua_chan_setfragments(kobj_t obj, void *data, uint32_t blocksize, uint32_t blockcount)
|
||||
{
|
||||
return (uaudio_chan_set_param_fragments(data, blocksize, blockcount));
|
||||
}
|
||||
|
||||
static int
|
||||
ua_chan_trigger(kobj_t obj, void *data, int go)
|
||||
{
|
||||
@@ -114,7 +108,6 @@ static kobj_method_t ua_chan_methods[] = {
|
||||
KOBJMETHOD(channel_setformat, ua_chan_setformat),
|
||||
KOBJMETHOD(channel_setspeed, ua_chan_setspeed),
|
||||
KOBJMETHOD(channel_setblocksize, ua_chan_setblocksize),
|
||||
KOBJMETHOD(channel_setfragments, ua_chan_setfragments),
|
||||
KOBJMETHOD(channel_trigger, ua_chan_trigger),
|
||||
KOBJMETHOD(channel_getptr, ua_chan_getptr),
|
||||
KOBJMETHOD(channel_getcaps, ua_chan_getcaps),
|
||||
|
||||
Reference in new issue
Block a user