move various fields from pcm_channel to snd_dbuf
improve chn_read code- don't stop/restart on overrun, just dump data more error checking on ioctls
This commit is contained in:
parent
04553e63a5
commit
d28089a10d
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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) |
|
||||
if (*arg_i == 1 || *arg_i == 2) {
|
||||
if (wrch)
|
||||
ret = chn_setformat(wrch, (wrch->format & ~AFMT_STEREO) |
|
||||
((*arg_i == 2)? AFMT_STEREO : 0));
|
||||
if (rdch) chn_setformat(rdch, (rdch->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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user