implement settrigger according to spec

fixes for non-blocking mode
This commit is contained in:
Cameron Grant 2000-04-23 18:09:18 +00:00
parent c22ae8f672
commit a0e22dd8db
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=59577
3 changed files with 40 additions and 27 deletions

View File

@ -115,12 +115,14 @@ static int
chn_polltrigger(pcm_channel *c)
{
snd_dbuf *bs = &c->buffer2nd;
unsigned lim = (c->flags & CHN_F_HAS_SIZE)? c->blocksize2nd : 1;
unsigned lim = (c->flags & CHN_F_HAS_SIZE)? c->blocksize2nd : 0;
int trig = 0;
lim = 0;
if (c->flags & CHN_F_MAPPED)
trig = ((bs->int_count > bs->prev_int_count) || bs->first_poll);
else trig = (((c->direction == PCMDIR_PLAY)? bs->fl : bs->rl) > lim);
else
trig = (((c->direction == PCMDIR_PLAY)? bs->fl : bs->rl) > lim);
return trig;
}
@ -387,7 +389,7 @@ chn_wrintr(pcm_channel *c)
/* 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) {
if (start & !(c->flags & CHN_F_NOTRIGGER)) {
chn_dmaupdate(c);
if (c->flags & CHN_F_MAPPED) l = c->blocksize;
else l = min(b->rl, c->blocksize) & DMA_ALIGN_MASK;
@ -465,10 +467,13 @@ chn_write(pcm_channel *c, struct uio *buf)
* the write operation avoids blocking.
*/
if ((c->flags & CHN_F_NBIO) && buf->uio_resid > c->blocksize2nd) {
DEB(printf("pcm warning: broken app, nbio and tried to write %d bytes with fragsz %d\n",
buf->uio_resid, c->blocksize2nd));
newsize = 16;
while (newsize < min(buf->uio_resid, CHN_2NDBUFMAXSIZE / c->fragments))
while (newsize < min(buf->uio_resid, CHN_2NDBUFMAXSIZE / 2))
newsize <<= 1;
chn_setblocksize(c, c->fragments, c->fragments);
chn_setblocksize(c, c->fragments, newsize);
DEB(printf("pcm warning: frags reset to %d x %d\n", c->fragments, c->blocksize2nd));
}
/* Store the initial size in the uio. */
@ -482,18 +487,15 @@ 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)
ret = EAGAIN;
/* Start playing if not yet. */
if ((bs->rl || b->rl) && !b->dl) {
if ((bs->rl || b->rl) && !b->dl)
chn_intr(c);
}
if (c->flags & CHN_F_NBIO) {
/* If no pcm data was written on nonblocking, return EAGAIN. */
if (buf->uio_resid == res)
ret = EAGAIN;
} else {
/* Wait until all samples are played in blocking mode. */
if (ret == 0) {
/* Wait until all samples are played in blocking mode. */
while (buf->uio_resid > 0) {
/* Check for underflow before writing into the buffers. */
chn_checkunderflow(c);
@ -501,7 +503,8 @@ chn_write(pcm_channel *c, struct uio *buf)
while (chn_wrfeed2nd(c, buf) > 0);
/* Start playing if necessary. */
if ((bs->rl || b->rl) && !b->dl) chn_intr(c);
if ((bs->rl || b->rl) && !b->dl)
chn_intr(c);
/* Have we finished to feed the secondary buffer? */
if (buf->uio_resid == 0)
@ -513,9 +516,11 @@ chn_write(pcm_channel *c, struct uio *buf)
ret = tsleep(b, PRIBIO | PCATCH, "pcmwr", timeout);
s = spltty();
/* if (ret == EINTR) chn_abort(c); */
if (ret == EINTR || ret == ERESTART) break;
if (ret == EINTR || ret == ERESTART)
break;
}
}
} else
ret = 0;
c->flags &= ~CHN_F_WRITING;
splx(s);
return ret;
@ -1156,15 +1161,18 @@ chn_setblocksize(pcm_channel *c, int blkcnt, int blksz)
return EINVAL;
}
c->flags &= ~CHN_F_HAS_SIZE;
if (blksz >= 2) c->flags |= CHN_F_HAS_SIZE;
if (blksz >= 2)
c->flags |= CHN_F_HAS_SIZE;
/* let us specify blksz without setting CHN_F_HAS_SIZE */
if (blksz < 0) blksz = -blksz;
if (blksz < 0)
blksz = -blksz;
/* default to blksz = ~0.25s */
if (blksz < 16) blksz = (c->buffer.sample_size * c->speed) >> 2;
if (blksz < 16)
blksz = (c->buffer.sample_size * c->speed) >> 2;
if (blkcnt * blksz > CHN_2NDBUFMAXSIZE)
blkcnt = CHN_2NDBUFMAXSIZE / blksz;
bufsz = blkcnt * blksz;
if (blksz < 16 || bufsz > CHN_2NDBUFMAXSIZE)
return EINVAL;
s = spltty();
if (bs->buf != NULL)

View File

@ -73,6 +73,7 @@ extern pcm_feeder feeder_root;
#define CHN_F_PENDING_IO (CHN_F_READING | CHN_F_WRITING)
#define CHN_F_RUNNING 0x00000010 /* dma is running */
#define CHN_F_TRIGGERED 0x00000020
#define CHN_F_NOTRIGGER 0x00000040
#define CHN_F_BUSY 0x00001000 /* has been opened */
#define CHN_F_HAS_SIZE 0x00002000 /* user set block size */

View File

@ -291,6 +291,7 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
printf("AIOSYNC chan 0x%03lx pos %lu unimplemented\n",
((snd_sync_parm *)arg)->chan, ((snd_sync_parm *)arg)->pos);
break;
#endif
/*
* here follow the standard ioctls (filio.h etc.)
*/
@ -303,11 +304,9 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
case FIOASYNC: /*set/clear async i/o */
DEB( printf("FIOASYNC\n") ; )
break;
#endif
case SNDCTL_DSP_NONBLOCK:
#ifdef OLDPCM_IOCTL
case FIONBIO: /* set/clear non-blocking i/o */
#endif
if (rdch) rdch->flags &= ~CHN_F_NBIO;
if (wrch) wrch->flags &= ~CHN_F_NBIO;
if (*arg_i) {
@ -417,12 +416,13 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
if (maxfrags * fragsz > CHN_2NDBUFMAXSIZE)
maxfrags = CHN_2NDBUFMAXSIZE / fragsz;
DEB(printf("SNDCTL_DSP_SETFRAGMENT %d frags, %d sz\n", maxfrags, fragsz));
if (rdch)
ret = chn_setblocksize(rdch, maxfrags, fragsz);
if (wrch && ret == 0)
ret = chn_setblocksize(wrch, maxfrags, fragsz);
*arg_i = (c->fragments << 16) | fragsz;
*arg_i = (c->fragments << 16) | c->blocksize;
}
break;
@ -525,15 +525,19 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
case SNDCTL_DSP_SETTRIGGER:
if (rdch) {
rdch->flags &= ~CHN_F_TRIGGERED;
rdch->flags &= ~(CHN_F_TRIGGERED | CHN_F_NOTRIGGER);
if (*arg_i & PCM_ENABLE_INPUT)
rdch->flags |= CHN_F_TRIGGERED;
else
rdch->flags |= CHN_F_NOTRIGGER;
chn_intr(rdch);
}
if (wrch) {
wrch->flags &= ~CHN_F_TRIGGERED;
wrch->flags &= ~(CHN_F_TRIGGERED | CHN_F_NOTRIGGER);
if (*arg_i & PCM_ENABLE_OUTPUT)
wrch->flags |= CHN_F_TRIGGERED;
else
wrch->flags |= CHN_F_NOTRIGGER;
chn_intr(wrch);
}
break;