aboutsummaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorCameron Grant <cg@FreeBSD.org>2000-05-26 21:55:13 +0000
committerCameron Grant <cg@FreeBSD.org>2000-05-26 21:55:13 +0000
commitd28089a10d16493efc7e5a2fb775576e8f47fd66 (patch)
tree578f56ffc7bb0277b7a6829d7ecc56b07aa0f7be /sys/dev
parent04553e63a5a58711ea8510a970d6e754f3348e75 (diff)
Notes
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/sound/pcm/channel.c284
-rw-r--r--sys/dev/sound/pcm/datatypes.h17
-rw-r--r--sys/dev/sound/pcm/dsp.c81
3 files changed, 209 insertions, 173 deletions
diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c
index c8d4d17e06b1..af2111213f99 100644
--- a/sys/dev/sound/pcm/channel.c
+++ b/sys/dev/sound/pcm/channel.c
@@ -42,6 +42,7 @@ static void buf_clear(snd_dbuf *b, u_int32_t fmt, int length);
static void chn_dmaupdate(pcm_channel *c);
static void chn_wrintr(pcm_channel *c);
static void chn_rdintr(pcm_channel *c);
+static u_int32_t chn_start(pcm_channel *c);
/*
* SOUND OUTPUT
@@ -115,11 +116,11 @@ static int
chn_polltrigger(pcm_channel *c)
{
snd_dbuf *bs = &c->buffer2nd;
- unsigned lim = (c->flags & CHN_F_HAS_SIZE)? c->blocksize2nd : 0;
+ unsigned lim = (c->flags & CHN_F_HAS_SIZE)? bs->blksz : 0;
int trig = 0;
if (c->flags & CHN_F_MAPPED)
- trig = ((bs->int_count > bs->prev_int_count) || bs->first_poll);
+ trig = ((bs->int_count > bs->prev_int_count) || bs->prev_int_count == 0);
else
trig = (((c->direction == PCMDIR_PLAY)? bs->fl : bs->rl) > lim);
return trig;
@@ -130,8 +131,8 @@ chn_pollreset(pcm_channel *c)
{
snd_dbuf *bs = &c->buffer2nd;
- if (c->flags & CHN_F_MAPPED) bs->prev_int_count = bs->int_count;
- bs->first_poll = 0;
+ if (c->flags & CHN_F_MAPPED)
+ bs->prev_int_count = bs->int_count;
return 1;
}
@@ -148,7 +149,8 @@ chn_dmadone(pcm_channel *c)
chn_checkunderflow(c);
else
chn_dmaupdate(c);
- if (ISA_DMA(b)) chn_isadmabounce(c); /* sync bounce buffer */
+ if (ISA_DMA(b))
+ chn_isadmabounce(c); /* sync bounce buffer */
b->int_count++;
}
@@ -250,7 +252,7 @@ chn_wrfeed(pcm_channel *c)
a = (1 << c->align) - 1;
lacc = 0;
if (c->flags & CHN_F_MAPPED) {
- bs->rl = min(c->blocksize, b->fl);
+ bs->rl = min(b->blksz, b->fl);
bs->fl = 0;
a = 0;
}
@@ -273,20 +275,21 @@ chn_wrfeed(pcm_channel *c)
b->fl -= l;
b->fp = (b->fp + l) % b->bufsize;
/* Clear the new space in the secondary buffer. */
- buf_clear(bs, c->hwfmt, l);
+ buf_clear(bs, bs->fmt, l);
/* Accumulate the total bytes of the moved samples. */
lacc += l;
/* A feed to the DMA buffer is equivalent to an interrupt. */
bs->total += l;
if (c->flags & CHN_F_MAPPED) {
- if (bs->total - bs->prev_total >= c->blocksize2nd) {
+ if (bs->total - bs->prev_total >= bs->blksz) {
bs->prev_total = bs->total;
bs->int_count++;
c->blocks++;
}
} else
bs->int_count++;
- if (bs->sel.si_pid && chn_polltrigger(c)) selwakeup(&bs->sel);
+ if (bs->sel.si_pid && chn_polltrigger(c))
+ selwakeup(&bs->sel);
}
return lacc;
@@ -313,12 +316,12 @@ chn_wrfeed2nd(pcm_channel *c, struct uio *buf)
l = min(bs->fl, bs->bufsize - bs->fp);
/* Move the samples, update the markers and pointers. */
w = c->feeder->feed(c->feeder, c, bs->buf + bs->fp, l, buf);
- if (w == 0) panic("no feed");
+ if (w == 0)
+ panic("no feed");
bs->rl += w;
bs->fl -= w;
bs->fp = (bs->fp + w) % bs->bufsize;
/* Accumulate the total bytes of the moved samples. */
- bs->total += w;
wacc += w;
/* If any pcm data gets moved, push it to the DMA buffer. */
@@ -337,13 +340,13 @@ static void
chn_wrintr(pcm_channel *c)
{
snd_dbuf *b = &c->buffer;
- int start, l;
if (b->underflow && !(c->flags & CHN_F_MAPPED)) {
/* printf("underflow return\n");
*/ return; /* nothing new happened */
}
- if (b->dl) chn_dmadone(c);
+ if (b->dl)
+ chn_dmadone(c);
/*
* start another dma operation only if have ready data in the buffer,
@@ -354,19 +357,6 @@ chn_wrintr(pcm_channel *c)
* needed when doing stereo and 16-bit.
*/
- /*
- * Prepare new space of at least c->blocksize in the DMA
- * buffer for mmap.
- */
- /*
- if (c->flags & CHN_F_MAPPED && b->fl < c->blocksize) {
- dl = c->blocksize - b->fl;
- b->fl += dl;
- b->rl -= dl;
- b->rp = (b->rp + dl) % b->bufsize;
- buf_clear(b, c->hwfmt, dl);
- }
- */
/* Check underflow and update the pointers. */
chn_checkunderflow(c);
@@ -379,26 +369,18 @@ chn_wrintr(pcm_channel *c)
chn_wrfeed(c);
else {
while (chn_wrfeed(c) > 0);
- buf_clear(b, c->hwfmt, b->fl);
+ buf_clear(b, b->fmt, b->fl);
}
chn_dmawakeup(c);
- if (c->flags & CHN_F_MAPPED)
- start = c->flags & CHN_F_TRIGGERED;
- else {
-/* printf("%d >= %d && !(%x & %x)\n", b->rl, DMA_ALIGN_THRESHOLD, c->flags, CHN_F_ABORTING | CHN_F_CLOSING);
-*/ start = (b->rl >= DMA_ALIGN_THRESHOLD && !(c->flags & CHN_F_ABORTING));
- }
- if (start & !(c->flags & CHN_F_NOTRIGGER)) {
+ if (c->flags & CHN_F_TRIGGERED) {
chn_dmaupdate(c);
- if (c->flags & CHN_F_MAPPED) l = c->blocksize;
- else l = min(b->rl, c->blocksize) & DMA_ALIGN_MASK;
/*
* check if we need to reprogram the DMA on the sound card.
* This happens if the size has changed from zero
*/
if (b->dl == 0) {
/* Start DMA operation */
- b->dl = c->blocksize; /* record new transfer size */
+ b->dl = b->blksz; /* record new transfer size */
chn_trigger(c, PCMTRIG_START);
}
/*
@@ -406,20 +388,22 @@ chn_wrintr(pcm_channel *c)
* the emulated-DMA buffer to the device itself.
*/
chn_trigger(c, PCMTRIG_EMLDMAWR);
- if (b->dl != l) {
- DEB(printf("near underflow %d, %d, %d\n", l, b->dl, b->fl));
+ if (b->rl < b->dl) {
+ DEB(printf("near underflow (%d < %d), %d\n", b->rl, b->dl, b->fl));
/*
* we are near to underflow condition, so to prevent
* audio 'clicks' clear next b->fl bytes
*/
- buf_clear(b, c->hwfmt, b->fl);
+ buf_clear(b, b->fmt, b->fl);
+ if (b->rl < DMA_ALIGN_THRESHOLD)
+ b->underflow = 1;
}
} else {
/* cannot start a new dma transfer */
DEB(printf("underflow, flags 0x%08x rp %d rl %d\n", c->flags, b->rp, b->rl));
if (b->dl) { /* DMA was active */
b->underflow = 1; /* set underflow flag */
- buf_clear(b, c->hwfmt, b->bufsize);
+ buf_clear(b, b->fmt, b->bufsize);
}
}
}
@@ -465,14 +449,14 @@ chn_write(pcm_channel *c, struct uio *buf)
* resulting partial write. Expand the block size so that
* the write operation avoids blocking.
*/
- if ((c->flags & CHN_F_NBIO) && buf->uio_resid > c->blocksize2nd) {
+ if ((c->flags & CHN_F_NBIO) && buf->uio_resid > bs->blksz) {
DEB(printf("pcm warning: broken app, nbio and tried to write %d bytes with fragsz %d\n",
- buf->uio_resid, c->blocksize2nd));
+ buf->uio_resid, bs->blksz));
newsize = 16;
while (newsize < min(buf->uio_resid, CHN_2NDBUFMAXSIZE / 2))
newsize <<= 1;
- chn_setblocksize(c, c->fragments, newsize);
- DEB(printf("pcm warning: frags reset to %d x %d\n", c->fragments, c->blocksize2nd));
+ chn_setblocksize(c, bs->blkcnt, newsize);
+ DEB(printf("pcm warning: frags reset to %d x %d\n", bs->blkcnt, bs->blksz));
}
/* Store the initial size in the uio. */
@@ -486,12 +470,12 @@ chn_write(pcm_channel *c, struct uio *buf)
/* Check for underflow before writing into the buffers. */
chn_checkunderflow(c);
while (chn_wrfeed2nd(c, buf) > 0);
- if (c->flags & CHN_F_NBIO && buf->uio_resid > 0)
+ if ((c->flags & CHN_F_NBIO) && (buf->uio_resid > 0))
ret = EAGAIN;
/* Start playing if not yet. */
- if ((bs->rl || b->rl) && !b->dl)
- chn_intr(c);
+ if (!b->dl)
+ chn_start(c);
if (ret == 0) {
/* Wait until all samples are played in blocking mode. */
@@ -501,19 +485,15 @@ chn_write(pcm_channel *c, struct uio *buf)
/* Fill up the buffers with new pcm data. */
while (chn_wrfeed2nd(c, buf) > 0);
- /* Start playing if necessary. */
- if ((bs->rl || b->rl) && !b->dl)
- chn_intr(c);
-
/* Have we finished to feed the secondary buffer? */
if (buf->uio_resid == 0)
break;
/* Wait for new free space to write new pcm samples. */
- splx(s);
+ /* splx(s); */
timeout = 1; /*(buf->uio_resid >= b->dl)? hz / 20 : 1; */
ret = tsleep(b, PRIBIO | PCATCH, "pcmwr", timeout);
- s = spltty();
+ /* s = spltty(); */
/* if (ret == EINTR) chn_abort(c); */
if (ret == EINTR || ret == ERESTART)
break;
@@ -555,6 +535,17 @@ rec_blocksize, and fallback to smaller sizes if no space is available.
*/
+static int
+chn_rddump(pcm_channel *c, int cnt)
+{
+ snd_dbuf *b = &c->buffer;
+
+ b->rl -= cnt;
+ b->fl += cnt;
+ b->rp = (b->rp + cnt) % b->bufsize;
+ return cnt;
+}
+
/*
* Feed new data from the read buffer. Can be called in the bottom half.
* Hence must be called at spltty.
@@ -578,13 +569,12 @@ chn_rdfeed(pcm_channel *c)
b->rl -= l;
b->fl += l;
b->rp = (b->rp + l) % b->bufsize;
- /* Clear the new space in the DMA buffer. */
- buf_clear(b, c->hwfmt, l);
/* Accumulate the total bytes of the moved samples. */
lacc += l;
/* A feed from the DMA buffer is equivalent to an interrupt. */
bs->int_count++;
- if (bs->sel.si_pid && chn_polltrigger(c)) selwakeup(&bs->sel);
+ if (bs->sel.si_pid && chn_polltrigger(c))
+ selwakeup(&bs->sel);
}
return lacc;
@@ -616,7 +606,7 @@ chn_rdfeed2nd(pcm_channel *c, struct uio *buf)
bs->rl -= w;
bs->rp = (bs->rp + w) % bs->bufsize;
/* Clear the new space in the secondary buffer. */
- buf_clear(bs, c->hwfmt, l);
+ buf_clear(bs, bs->fmt, l);
/* Accumulate the total bytes of the moved samples. */
bs->total += w;
wacc += w;
@@ -634,26 +624,11 @@ static void
chn_rdintr(pcm_channel *c)
{
snd_dbuf *b = &c->buffer;
- snd_dbuf *bs = &c->buffer2nd;
- int start, dl;
if (b->dl) chn_dmadone(c);
DEB(printf("rdintr: start dl %d, rp:rl %d:%d, fp:fl %d:%d\n",
b->dl, b->rp, b->rl, b->fp, b->fl));
- /* Restart if have enough free space to absorb overruns */
-
- /*
- * Prepare new space of at least c->blocksize in the secondary
- * buffer for mmap.
- */
- if (c->flags & CHN_F_MAPPED && bs->fl < c->blocksize) {
- dl = c->blocksize - bs->fl;
- bs->fl += dl;
- bs->rl -= dl;
- bs->rp = (bs->rp + dl) % bs->bufsize;
- buf_clear(bs, c->hwfmt, dl);
- }
/* Update the pointers. */
chn_dmaupdate(c);
@@ -665,27 +640,27 @@ chn_rdintr(pcm_channel *c)
*/
while(chn_rdfeed(c) > 0);
chn_dmawakeup(c);
- if (c->flags & CHN_F_MAPPED)
- start = c->flags & CHN_F_TRIGGERED;
- else
- start = (b->fl > 0x200 && !(c->flags & CHN_F_ABORTING));
- if (start) {
- int l = min(b->fl - 0x100, c->blocksize);
- if (c->flags & CHN_F_MAPPED) l = c->blocksize;
- l &= DMA_ALIGN_MASK ; /* realign sizes */
- DEB(printf("rdintr: dl %d -> %d\n", b->dl, l);)
- if (l != b->dl) {
- /* size has changed. Stop and restart */
- if (b->dl) {
- chn_trigger(c, PCMTRIG_STOP);
- chn_dmaupdate(c);
- l = min(b->fl - 0x100, c->blocksize);
- l &= DMA_ALIGN_MASK ; /* realign sizes */
- }
- b->dl = l;
+ if (b->fl < b->dl) {
+ DEB(printf("near overflow (%d < %d), %d\n", b->fl, b->dl, b->rl));
+ chn_rddump(c, b->blksz - b->fl);
+ }
+
+ if (c->flags & CHN_F_TRIGGERED) {
+ /*
+ * check if we need to reprogram the DMA on the sound card.
+ * This happens if the size has changed from zero
+ */
+ if (b->dl == 0) {
+ /* Start DMA operation */
+ b->dl = b->blksz; /* record new transfer size */
chn_trigger(c, PCMTRIG_START);
}
+ /*
+ * Emulate writing by DMA, i.e. transfer the pcm data from
+ * the emulated-DMA buffer to the device itself.
+ */
+ chn_trigger(c, PCMTRIG_EMLDMARD);
} else {
if (b->dl) { /* was active */
b->dl = 0;
@@ -734,15 +709,17 @@ chn_read(pcm_channel *c, struct uio *buf)
c->flags |= CHN_F_READING;
c->flags &= ~CHN_F_ABORTING;
- limit = buf->uio_resid - c->blocksize;
- if (limit < 0) limit = 0;
+ limit = buf->uio_resid - b->blksz;
+ if (limit < 0)
+ limit = 0;
/* Update the pointers and suck up the DMA and secondary buffers. */
chn_dmaupdate(c);
while (chn_rdfeed2nd(c, buf) > 0);
/* Start capturing if not yet. */
- if ((!bs->rl || !b->rl) && !b->dl) chn_intr(c);
+ if ((!bs->rl || !b->rl) && !b->dl)
+ chn_start(c);
if (!(c->flags & CHN_F_NBIO)) {
/* Wait until all samples are captured. */
@@ -751,20 +728,18 @@ chn_read(pcm_channel *c, struct uio *buf)
chn_dmaupdate(c);
while (chn_rdfeed2nd(c, buf) > 0);
- /* Start capturing if necessary. */
- if ((!bs->rl || !b->rl) && !b->dl) chn_intr(c);
-
/* Have we finished to feed the uio? */
if (buf->uio_resid == 0)
break;
/* Wait for new pcm samples. */
- splx(s);
+ /* splx(s); */
timeout = (buf->uio_resid - limit >= b->dl)? hz / 20 : 1;
ret = tsleep(b, PRIBIO | PCATCH, "pcmrd", timeout);
- s = spltty();
- if (ret == EINTR) chn_abort(c);
- if (ret == EINTR || ret == ERESTART) break;
+ /* s = spltty(); */
+ /* if (ret == EINTR) chn_abort(c); */
+ if (ret == EINTR || ret == ERESTART)
+ break;
}
} else {
/* If no pcm data was read on nonblocking, return EAGAIN. */
@@ -787,6 +762,33 @@ chn_intr(pcm_channel *c)
chn_rdintr(c);
}
+u_int32_t
+chn_start(pcm_channel *c)
+{
+ u_int32_t r, s;
+ snd_dbuf *b = &c->buffer;
+
+ r = 0;
+ s = spltty();
+ if (b->dl == 0 && !(c->flags & (CHN_F_MAPPED | CHN_F_NOTRIGGER))) {
+ if (c->direction == PCMDIR_PLAY) {
+ /* Fill up the DMA buffer. */
+ while (chn_wrfeed(c) > 0);
+ if (b->rl >= b->blksz)
+ r = CHN_F_TRIGGERED;
+ } else {
+ /* Suck up the DMA buffer. */
+ while (chn_rdfeed(c) > 0);
+ if (b->fl >= b->blksz)
+ r = CHN_F_TRIGGERED;
+ }
+ c->flags |= r;
+ chn_intr(c);
+ }
+ splx(s);
+ return r;
+}
+
static void
chn_dma_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
{
@@ -857,29 +859,23 @@ chn_resetbuf(pcm_channel *c)
snd_dbuf *bs = &c->buffer2nd;
c->blocks = 0;
- b->sample_size = 1;
- b->sample_size <<= (c->hwfmt & AFMT_STEREO)? 1 : 0;
- b->sample_size <<= (c->hwfmt & AFMT_16BIT)? 1 : 0;
-
b->rp = b->fp = 0;
b->dl = b->rl = 0;
b->fl = b->bufsize;
b->prev_total = b->total = 0;
b->prev_int_count = b->int_count = 0;
- b->first_poll = 1;
b->underflow = 0;
if (b->buf && b->bufsize > 0)
- buf_clear(b, c->hwfmt, b->bufsize);
+ buf_clear(b, b->fmt, b->bufsize);
bs->rp = bs->fp = 0;
bs->dl = bs->rl = 0;
bs->fl = bs->bufsize;
bs->prev_total = bs->total = 0;
- b->prev_int_count = b->int_count = 0;
- b->first_poll = 1;
- b->underflow = 0;
+ bs->prev_int_count = bs->int_count = 0;
+ bs->underflow = 0;
if (bs->buf && bs->bufsize > 0)
- buf_clear(bs, c->hwfmt, bs->bufsize);
+ buf_clear(bs, bs->fmt, bs->bufsize);
}
void
@@ -908,7 +904,8 @@ buf_isadmaptr(snd_dbuf *b)
{
if (ISA_DMA(b)) {
int i = b->dl? isa_dmastatus(b->chan) : b->bufsize;
- if (i < 0) i = 0;
+ if (i < 0)
+ i = 0;
return b->bufsize - i;
} else KASSERT(1, ("buf_isadmaptr called on invalid channel"));
return -1;
@@ -965,7 +962,7 @@ chn_poll(pcm_channel *c, int ev, struct proc *p)
while (chn_rdfeed(c) > 0);
}
if (!b->dl)
- chn_intr(c);
+ chn_start(c);
}
ret = 0;
if (chn_polltrigger(c) && chn_pollreset(c))
@@ -990,6 +987,7 @@ chn_abort(pcm_channel *c)
if (!b->dl) return 0;
c->flags |= CHN_F_ABORTING;
+ c->flags &= ~CHN_F_TRIGGERED;
while (!b->underflow && (b->dl > 0) && (cnt < 20)) {
tsleep((caddr_t)b, PRIBIO, "pcmabr", hz / 20);
cnt++;
@@ -1038,14 +1036,15 @@ chn_flush(pcm_channel *c)
if (count == 0)
DEB(printf("chn_flush: timeout flushing dbuf_out, cnt 0x%x flags 0x%x\n", b->rl, c->flags));
c->flags &= ~CHN_F_CLOSING;
- if (c->direction == PCMDIR_PLAY && b->dl) chn_abort(c);
+ if (c->direction == PCMDIR_PLAY && b->dl)
+ chn_abort(c);
return 0;
}
int
chn_reset(pcm_channel *c, u_int32_t fmt)
{
- int r;
+ int r = 0;
chn_abort(c);
c->flags &= CHN_F_RESET;
@@ -1053,12 +1052,14 @@ chn_reset(pcm_channel *c, u_int32_t fmt)
if (r)
return r;
if (fmt) {
- c->format = fmt;
- c->speed = DSP_DEFAULT_SPEED;
- c->volume = (100 << 8) | 100;
+ r = chn_setformat(c, fmt);
+ if (r == 0)
+ r = chn_setspeed(c, DSP_DEFAULT_SPEED);
+ if (r == 0)
+ r = chn_setvolume(c, 100, 100);
}
chn_resetbuf(c);
- c->flags |= CHN_F_INIT;
+ /* c->flags |= CHN_F_INIT; */
return 0;
}
@@ -1112,7 +1113,8 @@ chn_setvolume(pcm_channel *c, int left, int right)
{
/* could add a feeder for volume changing if channel returns -1 */
if (CANCHANGE(c)) {
- return -1;
+ c->volume = (left << 8) | right;
+ return 0;
}
c->volume = (left << 8) | right;
c->flags |= CHN_F_INIT;
@@ -1122,10 +1124,12 @@ chn_setvolume(pcm_channel *c, int left, int right)
int
chn_setspeed(pcm_channel *c, int speed)
{
+ if (speed <= 0)
+ return EINVAL;
/* could add a feeder for rate conversion */
if (CANCHANGE(c)) {
c->speed = c->setspeed(c->devinfo, speed);
- return c->speed;
+ return 0;
}
c->speed = speed;
c->flags |= CHN_F_INIT;
@@ -1135,12 +1139,20 @@ chn_setspeed(pcm_channel *c, int speed)
int
chn_setformat(pcm_channel *c, u_int32_t fmt)
{
+ snd_dbuf *b = &c->buffer;
+ snd_dbuf *bs = &c->buffer2nd;
+
+ u_int32_t hwfmt;
if (CANCHANGE(c)) {
- c->hwfmt = c->format = fmt;
- c->hwfmt = chn_feedchain(c);
+ c->format = fmt;
+ hwfmt = chn_feedchain(c);
+ if ((c->flags & CHN_F_MAPPED) && c->format != hwfmt)
+ return EINVAL;
+ b->fmt = hwfmt;
+ bs->fmt = hwfmt;
chn_resetbuf(c);
- c->setformat(c->devinfo, c->hwfmt);
- return fmt;
+ c->setformat(c->devinfo, hwfmt);
+ return 0;
}
c->format = fmt;
c->flags |= CHN_F_INIT;
@@ -1150,16 +1162,22 @@ chn_setformat(pcm_channel *c, u_int32_t fmt)
int
chn_setblocksize(pcm_channel *c, int blkcnt, int blksz)
{
+ snd_dbuf *b = &c->buffer;
snd_dbuf *bs = &c->buffer2nd;
- int s, bufsz;
+ int s, ss, bufsz;
- if (c->fragments == blkcnt && c->blocksize2nd == blksz)
+ if (bs->blkcnt == blkcnt && bs->blksz == blksz)
return 0;
if (c->flags & CHN_F_MAPPED) {
DEB(printf("chn_setblocksize: can't work on mapped channel"));
return EINVAL;
}
c->flags &= ~CHN_F_HAS_SIZE;
+
+ ss = 1;
+ ss <<= (bs->fmt & AFMT_STEREO)? 1 : 0;
+ ss <<= (bs->fmt & AFMT_16BIT)? 1 : 0;
+
if (blksz >= 2)
c->flags |= CHN_F_HAS_SIZE;
/* let us specify blksz without setting CHN_F_HAS_SIZE */
@@ -1167,7 +1185,7 @@ chn_setblocksize(pcm_channel *c, int blkcnt, int blksz)
blksz = -blksz;
/* default to blksz = ~0.25s */
if (blksz < 16)
- blksz = (c->buffer.sample_size * c->speed) >> 2;
+ blksz = (ss * c->speed) >> 2;
if (blkcnt * blksz > CHN_2NDBUFMAXSIZE)
blkcnt = CHN_2NDBUFMAXSIZE / blksz;
@@ -1185,11 +1203,11 @@ chn_setblocksize(pcm_channel *c, int blkcnt, int blksz)
bs->bufsize = bufsz;
bs->rl = bs->rp = bs->fp = 0;
bs->fl = bs->bufsize;
- buf_clear(bs, c->hwfmt, bs->bufsize);
- c->fragments = blkcnt;
- c->blocksize2nd = blksz;
- RANGE(blksz, 16, c->buffer.bufsize / 2);
- c->blocksize = c->setblocksize(c->devinfo, blksz);
+ buf_clear(bs, bs->fmt, bs->bufsize);
+ bs->blkcnt = blkcnt;
+ bs->blksz = blksz;
+ RANGE(blksz, 16, b->bufsize / 2);
+ b->blksz = c->setblocksize(c->devinfo, blksz);
splx(s);
return 0;
diff --git a/sys/dev/sound/pcm/datatypes.h b/sys/dev/sound/pcm/datatypes.h
index 550d0b7b1984..67e1923fda4d 100644
--- a/sys/dev/sound/pcm/datatypes.h
+++ b/sys/dev/sound/pcm/datatypes.h
@@ -60,18 +60,16 @@ struct _snd_mixer {
struct _snd_dbuf {
u_int8_t *buf;
int bufsize;
- volatile int rp, fp; /* pointers to the ready and free area */
volatile int dl; /* transfer size */
+ volatile int rp, fp; /* pointers to the ready and free area */
volatile int rl, fl; /* lenght of ready and free areas. */
volatile u_int32_t int_count, prev_int_count;
+ volatile u_int32_t total, prev_total;
int chan, dir; /* dma channel */
- int sample_size; /* 1, 2, 4 */
- struct selinfo sel;
- u_long total; /* total bytes processed */
- u_long prev_total; /* copy of the above when GETxPTR called */
- int first_poll;
- bus_dmamap_t dmamap;
+ int fmt, blksz, blkcnt;
int underflow;
+ bus_dmamap_t dmamap;
+ struct selinfo sel;
};
typedef int (pcmfeed_init_t)(pcm_feeder *feeder);
@@ -118,9 +116,8 @@ struct _pcm_channel {
int volume;
u_int32_t speed;
u_int32_t flags;
- u_int32_t format, hwfmt;
- u_int32_t blocksize, blocksize2nd;
- u_int32_t fragments, blocks;
+ u_int32_t format;
+ u_int32_t blocks;
int direction;
snd_dbuf buffer, buffer2nd;
diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c
index d609d0004671..4c56076886e0 100644
--- a/sys/dev/sound/pcm/dsp.c
+++ b/sys/dev/sound/pcm/dsp.c
@@ -227,8 +227,8 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
case AIOGSIZE: /* get the current blocksize */
{
struct snd_size *p = (struct snd_size *)arg;
- if (wrch) p->play_size = wrch->blocksize2nd;
- if (rdch) p->rec_size = rdch->blocksize2nd;
+ if (wrch) p->play_size = wrch->buffer2nd.blksz;
+ if (rdch) p->rec_size = rdch->buffer2nd.blksz;
}
break;
@@ -321,9 +321,9 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
case THE_REAL_SNDCTL_DSP_GETBLKSIZE:
case SNDCTL_DSP_GETBLKSIZE:
if (wrch)
- *arg_i = wrch->blocksize2nd;
+ *arg_i = wrch->buffer2nd.blksz;
else if (rdch)
- *arg_i = rdch->blocksize2nd;
+ *arg_i = rdch->buffer2nd.blksz;
else
*arg_i = 0;
break ;
@@ -349,8 +349,10 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
case SNDCTL_DSP_SPEED:
splx(s);
- if (wrch) chn_setspeed(wrch, *arg_i);
- if (rdch) chn_setspeed(rdch, *arg_i);
+ if (wrch)
+ ret = chn_setspeed(wrch, *arg_i);
+ if (rdch && ret == 0)
+ ret = chn_setspeed(rdch, *arg_i);
/* fallthru */
case SOUND_PCM_READ_RATE:
@@ -359,20 +361,29 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
case SNDCTL_DSP_STEREO:
splx(s);
- if (wrch) chn_setformat(wrch, (wrch->format & ~AFMT_STEREO) |
+ if (wrch)
+ ret = chn_setformat(wrch, (wrch->format & ~AFMT_STEREO) |
((*arg_i)? AFMT_STEREO : 0));
- if (rdch) chn_setformat(rdch, (rdch->format & ~AFMT_STEREO) |
+ if (rdch && ret == 0)
+ ret = chn_setformat(rdch, (rdch->format & ~AFMT_STEREO) |
((*arg_i)? AFMT_STEREO : 0));
*arg_i = ((wrch? wrch->format : rdch->format) & AFMT_STEREO)? 1 : 0;
break;
case SOUND_PCM_WRITE_CHANNELS:
+/* case SNDCTL_DSP_CHANNELS: ( == SOUND_PCM_WRITE_CHANNELS) */
splx(s);
- if (wrch) chn_setformat(wrch, (wrch->format & ~AFMT_STEREO) |
- ((*arg_i == 2)? AFMT_STEREO : 0));
- if (rdch) chn_setformat(rdch, (rdch->format & ~AFMT_STEREO) |
+ if (*arg_i == 1 || *arg_i == 2) {
+ if (wrch)
+ ret = chn_setformat(wrch, (wrch->format & ~AFMT_STEREO) |
((*arg_i == 2)? AFMT_STEREO : 0));
- /* fallthru */
+ if (rdch && ret == 0)
+ ret = chn_setformat(rdch, (rdch->format & ~AFMT_STEREO) |
+ ((*arg_i == 2)? AFMT_STEREO : 0));
+ *arg_i = ((wrch? wrch->format : rdch->format) & AFMT_STEREO)? 1 : 0;
+ } else
+ *arg_i = 0;
+ break;
case SOUND_PCM_READ_CHANNELS:
*arg_i = ((wrch? wrch->format : rdch->format) & AFMT_STEREO)? 2 : 1;
@@ -384,18 +395,19 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
case SNDCTL_DSP_SETFMT: /* sets _one_ format */
splx(s);
- if (wrch) chn_setformat(wrch, (*arg_i) | (wrch->format & AFMT_STEREO));
- if (rdch) chn_setformat(rdch, (*arg_i) | (rdch->format & AFMT_STEREO));
+ if (wrch)
+ ret = chn_setformat(wrch, (*arg_i) | (wrch->format & AFMT_STEREO));
+ if (rdch && ret == 0)
+ ret = chn_setformat(rdch, (*arg_i) | (rdch->format & AFMT_STEREO));
*arg_i = (wrch? wrch->format: rdch->format) & ~AFMT_STEREO;
break;
case SNDCTL_DSP_SUBDIVIDE:
/* XXX watch out, this is RW! */
- DEB(printf("SNDCTL_DSP_SUBDIVIDE unimplemented\n");)
+ printf("SNDCTL_DSP_SUBDIVIDE unimplemented\n");
break;
case SNDCTL_DSP_SETFRAGMENT:
- /* XXX watch out, this is RW! */
DEB(printf("SNDCTL_DSP_SETFRAGMENT 0x%08x\n", *(int *)arg));
{
pcm_channel *c = wrch? wrch : rdch;
@@ -421,7 +433,13 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
if (wrch && ret == 0)
ret = chn_setblocksize(wrch, maxfrags, fragsz);
- *arg_i = (c->fragments << 16) | c->blocksize;
+ fragsz = c->buffer2nd.blksz;
+ fragln = 0;
+ while (fragsz > 1) {
+ fragln++;
+ fragsz >>= 1;
+ }
+ *arg_i = (c->buffer2nd.blkcnt << 16) | fragln;
}
break;
@@ -439,9 +457,9 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
*/
while (chn_rdfeed(rdch) > 0);
a->bytes = bs->rl;
- a->fragments = a->bytes / rdch->blocksize2nd;
- a->fragstotal = rdch->fragments;
- a->fragsize = rdch->blocksize2nd;
+ a->fragments = a->bytes / rdch->buffer2nd.blksz;
+ a->fragstotal = rdch->buffer2nd.blkcnt;
+ a->fragsize = rdch->buffer2nd.blksz;
}
}
break;
@@ -463,9 +481,9 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
while (chn_wrfeed(wrch) > 0);
}
a->bytes = bs->fl;
- a->fragments = a->bytes / wrch->blocksize2nd;
- a->fragstotal = wrch->fragments;
- a->fragsize = wrch->blocksize2nd;
+ a->fragments = a->bytes / wrch->buffer2nd.blksz;
+ a->fragstotal = wrch->buffer2nd.blkcnt;
+ a->fragsize = wrch->buffer2nd.blksz;
}
}
break;
@@ -483,8 +501,9 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
*/
while (chn_rdfeed(rdch) > 0);
a->bytes = bs->total;
- a->blocks = bs->rl / rdch->blocksize2nd;
- a->ptr = bs->rl % rdch->blocksize2nd;
+ a->blocks = rdch->blocks;
+ a->ptr = bs->rp;
+ rdch->blocks = 0;
} else ret = EINVAL;
}
break;
@@ -601,12 +620,14 @@ dsp_mmap(snddev_info *d, int chan, vm_offset_t offset, int nprot)
getchns(d, chan, &rdch, &wrch);
/* XXX this is broken by line 204 of vm/device_pager.c, so force write buffer */
- if (1 || (wrch && (nprot & PROT_WRITE))) c = wrch;
- else if (rdch && (nprot & PROT_READ)) c = rdch;
- if (c) {
+ if (1 || (wrch && (nprot & PROT_WRITE)))
+ c = wrch;
+ else if (rdch && (nprot & PROT_READ))
+ c = rdch;
+ if (c && (c->format == c->buffer.fmt)) {
c->flags |= CHN_F_MAPPED;
return atop(vtophys(c->buffer2nd.buf + offset));
- }
- return -1;
+ } else
+ return -1;
}