diff --git a/sys/dev/pcm/channel.c b/sys/dev/pcm/channel.c index bb46e03f8e88..38e1796bee97 100644 --- a/sys/dev/pcm/channel.c +++ b/sys/dev/pcm/channel.c @@ -268,7 +268,7 @@ chn_write(pcm_channel *c, struct uio *buf) } a = (1 << c->align) - 1; c->flags |= CHN_F_WRITING; - while (buf->uio_resid > 0) { + while ((c->smegcnt + buf->uio_resid) > a) { s = spltty(); chn_dmaupdate(c); splx(s); @@ -282,10 +282,9 @@ chn_write(pcm_channel *c, struct uio *buf) continue; } /* ensure we always have a whole number of samples */ - l = min(b->fl, b->bufsize - b->fp); - if (l & a) panic("unaligned write %d, %d", l, a + 1); - l &= ~a; - w = c->feeder->feed(c->feeder, b->buf + b->fp, l, buf); + l = min(b->fl, b->bufsize - b->fp) & ~a; + if (l == 0) break; + w = c->feeder->feed(c->feeder, c, b->buf + b->fp, l, buf); if (w == 0) panic("no feed"); s = spltty(); b->rl += w; @@ -294,6 +293,12 @@ chn_write(pcm_channel *c, struct uio *buf) splx(s); if (b->rl && !b->dl) chn_stintr(c); } + if ((ret == 0) && (buf->uio_resid > 0)) { + l = buf->uio_resid; + if ((c->smegcnt + l) >= SMEGBUFSZ) panic("resid overflow %d", l); + uiomove(c->smegbuf + c->smegcnt, l, buf); + c->smegcnt += l; + } c->flags &= ~CHN_F_WRITING; return ret; } @@ -418,7 +423,7 @@ chn_read(pcm_channel *c, struct uio *buf) } /* ensure we always have a whole number of samples */ l = min(b->rl, b->bufsize - b->rp) & DMA_ALIGN_MASK; - w = c->feeder->feed(c->feeder, b->buf + b->rp, l, buf); + w = c->feeder->feed(c->feeder, c, b->buf + b->rp, l, buf); s = spltty(); b->rl -= w; b->fl += w; @@ -474,6 +479,7 @@ chn_resetbuf(pcm_channel *c) u_int16_t data, *p; u_int32_t i; + c->smegcnt = 0; c->buffer.sample_size = 1; c->buffer.sample_size <<= (c->hwfmt & AFMT_STEREO)? 1 : 0; c->buffer.sample_size <<= (c->hwfmt & AFMT_16BIT)? 1 : 0; diff --git a/sys/dev/pcm/datatypes.h b/sys/dev/pcm/datatypes.h index 4a38679e45c5..a4af384a1c01 100644 --- a/sys/dev/pcm/datatypes.h +++ b/sys/dev/pcm/datatypes.h @@ -75,7 +75,8 @@ struct _snd_dbuf { typedef int (pcmfeed_init_t)(pcm_feeder *feeder); typedef int (pcmfeed_free_t)(pcm_feeder *feeder); -typedef int (pcmfeed_feed_t)(pcm_feeder *feeder, u_int8_t *buffer, u_int32_t count, struct uio *stream); +typedef int (pcmfeed_feed_t)(pcm_feeder *feeder, pcm_channel *c, u_int8_t *buffer, + u_int32_t count, struct uio *stream); struct _pcm_feeder { char name[16]; @@ -121,6 +122,9 @@ struct _pcm_channel { int direction; snd_dbuf buffer; +#define SMEGBUFSZ 4 + u_int8_t smegbuf[SMEGBUFSZ]; + u_int32_t smegcnt; void *devinfo; }; diff --git a/sys/dev/pcm/feeder.c b/sys/dev/pcm/feeder.c index 4a59806803c7..055dc98d65df 100644 --- a/sys/dev/pcm/feeder.c +++ b/sys/dev/pcm/feeder.c @@ -106,10 +106,17 @@ static unsigned char u8_to_ulaw[] = { /*****************************************************************************/ static int -feed_root(pcm_feeder *feeder, u_int8_t *buffer, u_int32_t count, struct uio *stream) +feed_root(pcm_feeder *feeder, pcm_channel *ch, u_int8_t *buffer, u_int32_t count, struct uio *stream) { int ret, tmp = 0, c = 0; if (!count) panic("feed_root: count == 0"); + count &= ~((1 << ch->align) - 1); + if (!count) panic("feed_root: aligned count == 0"); + if (ch->smegcnt > 0) { + c = min(ch->smegcnt, count); + bcopy(ch->smegbuf, buffer, c); + ch->smegcnt -= c; + } while ((stream->uio_resid > 0) && (c < count)) { tmp = stream->uio_resid; ret = uiomove(buffer + c, count - c, stream); @@ -125,10 +132,10 @@ pcm_feeder feeder_root = { "root", 0, NULL, NULL, feed_root }; /*****************************************************************************/ static int -feed_8to16(pcm_feeder *f, u_int8_t *b, u_int32_t count, struct uio *stream) +feed_8to16(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) { int i, j, k; - k = f->source->feed(f->source, b, count / 2, stream); + k = f->source->feed(f->source, c, b, count / 2, stream); j = k - 1; i = j * 2 + 1; while (i > 0 && j >= 0) { @@ -157,11 +164,11 @@ feed_16to8_free(pcm_feeder *f) } static int -feed_16to8le(pcm_feeder *f, u_int8_t *b, u_int32_t count, struct uio *stream) +feed_16to8le(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) { u_int32_t i = 0, toget = count * 2; int j = 1, k; - k = f->source->feed(f->source, f->data, min(toget, FEEDBUFSZ), stream); + k = f->source->feed(f->source, c, f->data, min(toget, FEEDBUFSZ), stream); while (j < k) { b[i++] = ((u_int8_t *)f->data)[j]; j += 2; @@ -174,9 +181,9 @@ static pcm_feeder feeder_16to8le = /*****************************************************************************/ static int -feed_monotostereo8(pcm_feeder *f, u_int8_t *b, u_int32_t count, struct uio *stream) +feed_monotostereo8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) { - int i, j, k = f->source->feed(f->source, b, count / 2, stream); + int i, j, k = f->source->feed(f->source, c, b, count / 2, stream); j = k - 1; i = j * 2 + 1; while (i > 0 && j >= 0) { @@ -207,11 +214,11 @@ feed_stereotomono8_free(pcm_feeder *f) } static int -feed_stereotomono8(pcm_feeder *f, u_int8_t *b, u_int32_t count, struct uio *stream) +feed_stereotomono8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) { u_int32_t i = 0, toget = count * 2; int j = 0, k; - k = f->source->feed(f->source, f->data, min(toget, FEEDBUFSZ), stream); + k = f->source->feed(f->source, c, f->data, min(toget, FEEDBUFSZ), stream); while (j < k) { b[i++] = ((u_int8_t *)f->data)[j]; j += 2; @@ -225,10 +232,10 @@ static pcm_feeder feeder_stereotomono8 = /*****************************************************************************/ static int -feed_endian(pcm_feeder *f, u_int8_t *b, u_int32_t count, struct uio *stream) +feed_endian(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) { u_int8_t t; - int i = 0, j = f->source->feed(f->source, b, count, stream); + int i = 0, j = f->source->feed(f->source, c, b, count, stream); while (i < j) { t = b[i]; b[i] = b[i + 1]; @@ -242,9 +249,9 @@ static pcm_feeder feeder_endian = { "endian", -1, NULL, NULL, feed_endian }; /*****************************************************************************/ static int -feed_sign(pcm_feeder *f, u_int8_t *b, u_int32_t count, struct uio *stream) +feed_sign(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) { - int i = 0, j = f->source->feed(f->source, b, count, stream); + int i = 0, j = f->source->feed(f->source, c, b, count, stream); int ssz = (int)f->data, ofs = ssz - 1; while (i < j) { b[i + ofs] ^= 0x80; @@ -260,9 +267,9 @@ static pcm_feeder feeder_sign16 = /*****************************************************************************/ static int -feed_table(pcm_feeder *f, u_int8_t *b, u_int32_t count, struct uio *stream) +feed_table(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) { - int i = 0, j = f->source->feed(f->source, b, count, stream); + int i = 0, j = f->source->feed(f->source, c, b, count, stream); while (i < j) { b[i] = ((u_int8_t *)f->data)[b[i]]; i++; diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c index bb46e03f8e88..38e1796bee97 100644 --- a/sys/dev/sound/pcm/channel.c +++ b/sys/dev/sound/pcm/channel.c @@ -268,7 +268,7 @@ chn_write(pcm_channel *c, struct uio *buf) } a = (1 << c->align) - 1; c->flags |= CHN_F_WRITING; - while (buf->uio_resid > 0) { + while ((c->smegcnt + buf->uio_resid) > a) { s = spltty(); chn_dmaupdate(c); splx(s); @@ -282,10 +282,9 @@ chn_write(pcm_channel *c, struct uio *buf) continue; } /* ensure we always have a whole number of samples */ - l = min(b->fl, b->bufsize - b->fp); - if (l & a) panic("unaligned write %d, %d", l, a + 1); - l &= ~a; - w = c->feeder->feed(c->feeder, b->buf + b->fp, l, buf); + l = min(b->fl, b->bufsize - b->fp) & ~a; + if (l == 0) break; + w = c->feeder->feed(c->feeder, c, b->buf + b->fp, l, buf); if (w == 0) panic("no feed"); s = spltty(); b->rl += w; @@ -294,6 +293,12 @@ chn_write(pcm_channel *c, struct uio *buf) splx(s); if (b->rl && !b->dl) chn_stintr(c); } + if ((ret == 0) && (buf->uio_resid > 0)) { + l = buf->uio_resid; + if ((c->smegcnt + l) >= SMEGBUFSZ) panic("resid overflow %d", l); + uiomove(c->smegbuf + c->smegcnt, l, buf); + c->smegcnt += l; + } c->flags &= ~CHN_F_WRITING; return ret; } @@ -418,7 +423,7 @@ chn_read(pcm_channel *c, struct uio *buf) } /* ensure we always have a whole number of samples */ l = min(b->rl, b->bufsize - b->rp) & DMA_ALIGN_MASK; - w = c->feeder->feed(c->feeder, b->buf + b->rp, l, buf); + w = c->feeder->feed(c->feeder, c, b->buf + b->rp, l, buf); s = spltty(); b->rl -= w; b->fl += w; @@ -474,6 +479,7 @@ chn_resetbuf(pcm_channel *c) u_int16_t data, *p; u_int32_t i; + c->smegcnt = 0; c->buffer.sample_size = 1; c->buffer.sample_size <<= (c->hwfmt & AFMT_STEREO)? 1 : 0; c->buffer.sample_size <<= (c->hwfmt & AFMT_16BIT)? 1 : 0; diff --git a/sys/dev/sound/pcm/datatypes.h b/sys/dev/sound/pcm/datatypes.h index 4a38679e45c5..a4af384a1c01 100644 --- a/sys/dev/sound/pcm/datatypes.h +++ b/sys/dev/sound/pcm/datatypes.h @@ -75,7 +75,8 @@ struct _snd_dbuf { typedef int (pcmfeed_init_t)(pcm_feeder *feeder); typedef int (pcmfeed_free_t)(pcm_feeder *feeder); -typedef int (pcmfeed_feed_t)(pcm_feeder *feeder, u_int8_t *buffer, u_int32_t count, struct uio *stream); +typedef int (pcmfeed_feed_t)(pcm_feeder *feeder, pcm_channel *c, u_int8_t *buffer, + u_int32_t count, struct uio *stream); struct _pcm_feeder { char name[16]; @@ -121,6 +122,9 @@ struct _pcm_channel { int direction; snd_dbuf buffer; +#define SMEGBUFSZ 4 + u_int8_t smegbuf[SMEGBUFSZ]; + u_int32_t smegcnt; void *devinfo; }; diff --git a/sys/dev/sound/pcm/feeder.c b/sys/dev/sound/pcm/feeder.c index 4a59806803c7..055dc98d65df 100644 --- a/sys/dev/sound/pcm/feeder.c +++ b/sys/dev/sound/pcm/feeder.c @@ -106,10 +106,17 @@ static unsigned char u8_to_ulaw[] = { /*****************************************************************************/ static int -feed_root(pcm_feeder *feeder, u_int8_t *buffer, u_int32_t count, struct uio *stream) +feed_root(pcm_feeder *feeder, pcm_channel *ch, u_int8_t *buffer, u_int32_t count, struct uio *stream) { int ret, tmp = 0, c = 0; if (!count) panic("feed_root: count == 0"); + count &= ~((1 << ch->align) - 1); + if (!count) panic("feed_root: aligned count == 0"); + if (ch->smegcnt > 0) { + c = min(ch->smegcnt, count); + bcopy(ch->smegbuf, buffer, c); + ch->smegcnt -= c; + } while ((stream->uio_resid > 0) && (c < count)) { tmp = stream->uio_resid; ret = uiomove(buffer + c, count - c, stream); @@ -125,10 +132,10 @@ pcm_feeder feeder_root = { "root", 0, NULL, NULL, feed_root }; /*****************************************************************************/ static int -feed_8to16(pcm_feeder *f, u_int8_t *b, u_int32_t count, struct uio *stream) +feed_8to16(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) { int i, j, k; - k = f->source->feed(f->source, b, count / 2, stream); + k = f->source->feed(f->source, c, b, count / 2, stream); j = k - 1; i = j * 2 + 1; while (i > 0 && j >= 0) { @@ -157,11 +164,11 @@ feed_16to8_free(pcm_feeder *f) } static int -feed_16to8le(pcm_feeder *f, u_int8_t *b, u_int32_t count, struct uio *stream) +feed_16to8le(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) { u_int32_t i = 0, toget = count * 2; int j = 1, k; - k = f->source->feed(f->source, f->data, min(toget, FEEDBUFSZ), stream); + k = f->source->feed(f->source, c, f->data, min(toget, FEEDBUFSZ), stream); while (j < k) { b[i++] = ((u_int8_t *)f->data)[j]; j += 2; @@ -174,9 +181,9 @@ static pcm_feeder feeder_16to8le = /*****************************************************************************/ static int -feed_monotostereo8(pcm_feeder *f, u_int8_t *b, u_int32_t count, struct uio *stream) +feed_monotostereo8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) { - int i, j, k = f->source->feed(f->source, b, count / 2, stream); + int i, j, k = f->source->feed(f->source, c, b, count / 2, stream); j = k - 1; i = j * 2 + 1; while (i > 0 && j >= 0) { @@ -207,11 +214,11 @@ feed_stereotomono8_free(pcm_feeder *f) } static int -feed_stereotomono8(pcm_feeder *f, u_int8_t *b, u_int32_t count, struct uio *stream) +feed_stereotomono8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) { u_int32_t i = 0, toget = count * 2; int j = 0, k; - k = f->source->feed(f->source, f->data, min(toget, FEEDBUFSZ), stream); + k = f->source->feed(f->source, c, f->data, min(toget, FEEDBUFSZ), stream); while (j < k) { b[i++] = ((u_int8_t *)f->data)[j]; j += 2; @@ -225,10 +232,10 @@ static pcm_feeder feeder_stereotomono8 = /*****************************************************************************/ static int -feed_endian(pcm_feeder *f, u_int8_t *b, u_int32_t count, struct uio *stream) +feed_endian(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) { u_int8_t t; - int i = 0, j = f->source->feed(f->source, b, count, stream); + int i = 0, j = f->source->feed(f->source, c, b, count, stream); while (i < j) { t = b[i]; b[i] = b[i + 1]; @@ -242,9 +249,9 @@ static pcm_feeder feeder_endian = { "endian", -1, NULL, NULL, feed_endian }; /*****************************************************************************/ static int -feed_sign(pcm_feeder *f, u_int8_t *b, u_int32_t count, struct uio *stream) +feed_sign(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) { - int i = 0, j = f->source->feed(f->source, b, count, stream); + int i = 0, j = f->source->feed(f->source, c, b, count, stream); int ssz = (int)f->data, ofs = ssz - 1; while (i < j) { b[i + ofs] ^= 0x80; @@ -260,9 +267,9 @@ static pcm_feeder feeder_sign16 = /*****************************************************************************/ static int -feed_table(pcm_feeder *f, u_int8_t *b, u_int32_t count, struct uio *stream) +feed_table(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream) { - int i = 0, j = f->source->feed(f->source, b, count, stream); + int i = 0, j = f->source->feed(f->source, c, b, count, stream); while (i < j) { b[i] = ((u_int8_t *)f->data)[b[i]]; i++;