summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcg <cg@FreeBSD.org>2000-04-15 05:04:12 +0000
committercg <cg@FreeBSD.org>2000-04-15 05:04:12 +0000
commit6dcc92e9d30b104c9b7b5cb5dd7a0196735c50b1 (patch)
treef42ea1ef2636bf6e0eeb79e6acf3632afd5fc802
parent15ae5954179254ef21d7d580dae9975aa707623d (diff)
downloadFreeBSD-src-6dcc92e9d30b104c9b7b5cb5dd7a0196735c50b1.zip
FreeBSD-src-6dcc92e9d30b104c9b7b5cb5dd7a0196735c50b1.tar.gz
make mmap sort-of work. there seem to be interactions with certain hw
drivers, so still work in progress. do various mmap-related ioctls right. improve blocksize control. bits of cleanup.
-rw-r--r--sys/dev/sound/pcm/channel.c231
-rw-r--r--sys/dev/sound/pcm/channel.h4
-rw-r--r--sys/dev/sound/pcm/datatypes.h11
-rw-r--r--sys/dev/sound/pcm/dsp.c75
-rw-r--r--sys/dev/sound/pcm/feeder.c5
5 files changed, 172 insertions, 154 deletions
diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c
index 91a5cd6..52fa581 100644
--- a/sys/dev/sound/pcm/channel.c
+++ b/sys/dev/sound/pcm/channel.c
@@ -38,7 +38,7 @@
/*
#define DEB(x) x
*/
-static void chn_clearbuf(pcm_channel *c, snd_dbuf *b, int length);
+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);
@@ -127,7 +127,7 @@ chn_polltrigger(pcm_channel *c)
static int
chn_pollreset(pcm_channel *c)
{
- snd_dbuf *bs = &c->buffer;
+ snd_dbuf *bs = &c->buffer2nd;
if (c->flags & CHN_F_MAPPED) bs->prev_int_count = bs->int_count;
bs->first_poll = 0;
@@ -248,6 +248,15 @@ chn_wrfeed(pcm_channel *c)
/* ensure we always have a whole number of samples */
a = (1 << c->align) - 1;
lacc = 0;
+ if (c->flags & CHN_F_MAPPED) {
+ bs->rl = min(c->blocksize, b->fl);
+ bs->fl = 0;
+ a = 0;
+ }
+ /*
+ printf("b: [rl: %d, rp %d, fl %d, fp %d]; bs: [rl: %d, rp %d, fl %d, fp %d]\n",
+ b->rl, b->rp, b->fl, b->fp, bs->rl, bs->rp, bs->fl, bs->fp);
+ */
/* Don't allow write unaligned data */
while (bs->rl > a && b->fl > a) {
/* ensure we always have a whole number of samples */
@@ -263,11 +272,19 @@ chn_wrfeed(pcm_channel *c)
b->fl -= l;
b->fp = (b->fp + l) % b->bufsize;
/* Clear the new space in the secondary buffer. */
- chn_clearbuf(c, bs, l);
+ buf_clear(bs, c->hwfmt, l);
/* Accumulate the total bytes of the moved samples. */
lacc += l;
/* A feed to the DMA buffer is equivalent to an interrupt. */
- bs->int_count++;
+ bs->total += l;
+ if (c->flags & CHN_F_MAPPED) {
+ if (bs->total - bs->prev_total >= c->blocksize2nd) {
+ 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);
}
@@ -340,14 +357,15 @@ chn_wrintr(pcm_channel *c)
* 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;
- chn_clearbuf(c, b, dl);
+ buf_clear(b, c->hwfmt, dl);
}
-
+ */
/* Check underflow and update the pointers. */
chn_checkunderflow(c);
@@ -356,8 +374,12 @@ chn_wrintr(pcm_channel *c)
* If some of the pcm data in uio are still left, the top half
* goes to sleep by itself.
*/
- while (chn_wrfeed(c) > 0);
- chn_clearbuf(c, b, b->fl);
+ if (c->flags & CHN_F_MAPPED)
+ chn_wrfeed(c);
+ else {
+ while (chn_wrfeed(c) > 0);
+ buf_clear(b, c->hwfmt, b->fl);
+ }
chn_dmawakeup(c);
if (c->flags & CHN_F_MAPPED)
start = c->flags & CHN_F_TRIGGERED;
@@ -389,14 +411,14 @@ chn_wrintr(pcm_channel *c)
* we are near to underflow condition, so to prevent
* audio 'clicks' clear next b->fl bytes
*/
- chn_clearbuf(c, b, b->fl);
+ buf_clear(b, c->hwfmt, b->fl);
}
} 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 */
- chn_clearbuf(c, b, b->bufsize); /* and clear all DMA buffer */
+ buf_clear(b, c->hwfmt, b->bufsize);
}
}
}
@@ -443,10 +465,10 @@ chn_write(pcm_channel *c, struct uio *buf)
* the write operation avoids blocking.
*/
if ((c->flags & CHN_F_NBIO) && buf->uio_resid > c->blocksize2nd) {
- for (newsize = 1 ; newsize < min(buf->uio_resid, CHN_2NDBUFWHOLESIZE) ; newsize <<= 1);
- chn_setblocksize(c, newsize * c->fragments);
- c->blocksize2nd = newsize;
- c->fragments = bs->bufsize / c->blocksize2nd;
+ newsize = 16;
+ while (newsize < min(buf->uio_resid, CHN_2NDBUFMAXSIZE / c->fragments))
+ newsize <<= 1;
+ chn_setblocksize(c, c->fragments, c->fragments);
}
/* Store the initial size in the uio. */
@@ -553,7 +575,7 @@ chn_rdfeed(pcm_channel *c)
b->fl += l;
b->rp = (b->rp + l) % b->bufsize;
/* Clear the new space in the DMA buffer. */
- chn_clearbuf(c, b, l);
+ 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. */
@@ -590,7 +612,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. */
- chn_clearbuf(c, bs, l);
+ buf_clear(bs, c->hwfmt, l);
/* Accumulate the total bytes of the moved samples. */
bs->total += w;
wacc += w;
@@ -626,7 +648,7 @@ chn_rdintr(pcm_channel *c)
bs->fl += dl;
bs->rl -= dl;
bs->rp = (bs->rp + dl) % bs->bufsize;
- chn_clearbuf(c, bs, dl);
+ buf_clear(bs, c->hwfmt, dl);
}
/* Update the pointers. */
@@ -783,23 +805,40 @@ chn_allocbuf(snd_dbuf *b, bus_dma_tag_t parent_dmat)
}
static void
-chn_clearbuf(pcm_channel *c, snd_dbuf *b, int length)
+buf_clear(snd_dbuf *b, u_int32_t fmt, int length)
{
int i;
u_int16_t data, *p;
/* rely on length & DMA_ALIGN_MASK == 0 */
- length&=DMA_ALIGN_MASK;
- if (c->hwfmt & AFMT_SIGNED) data = 0x00; else data = 0x80;
- if (c->hwfmt & AFMT_16BIT) data <<= 8; else data |= data << 8;
- if (c->hwfmt & AFMT_BIGENDIAN)
+ length &= DMA_ALIGN_MASK;
+ if (length == 0)
+ return;
+
+ if (fmt & AFMT_SIGNED)
+ data = 0x00;
+ else
+ data = 0x80;
+
+ if (fmt & AFMT_16BIT)
+ data <<= 8;
+ else
+ data |= data << 8;
+
+ if (fmt & AFMT_BIGENDIAN)
data = ((data >> 8) & 0x00ff) | ((data << 8) & 0xff00);
- for (i = b->fp, p=(u_int16_t*)(b->buf+b->fp) ; i < b->bufsize && length; i += 2, length-=2)
- *p++ = data;
- for (i = 0, p=(u_int16_t*)b->buf; i < b->bufsize && length; i += 2, length-=2)
- *p++ = data;
- return;
+ i = b->fp;
+ p = (u_int16_t *)(b->buf + b->fp);
+ while (length > 0) {
+ *p++ = data;
+ length -= 2;
+ i += 2;
+ if (i >= b->bufsize) {
+ p = (u_int16_t *)b->buf;
+ i = 0;
+ }
+ }
}
void
@@ -808,8 +847,7 @@ chn_resetbuf(pcm_channel *c)
snd_dbuf *b = &c->buffer;
snd_dbuf *bs = &c->buffer2nd;
- c->smegcnt = 0;
-
+ 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;
@@ -821,7 +859,8 @@ chn_resetbuf(pcm_channel *c)
b->prev_int_count = b->int_count = 0;
b->first_poll = 1;
b->underflow = 0;
- chn_clearbuf(c, b, b->bufsize);
+ if (b->buf && b->bufsize > 0)
+ buf_clear(b, c->hwfmt, b->bufsize);
bs->rp = bs->fp = 0;
bs->dl = bs->rl = 0;
@@ -830,7 +869,8 @@ chn_resetbuf(pcm_channel *c)
b->prev_int_count = b->int_count = 0;
b->first_poll = 1;
b->underflow = 0;
- chn_clearbuf(c, bs, bs->bufsize);
+ if (bs->buf && bs->bufsize > 0)
+ buf_clear(bs, c->hwfmt, bs->bufsize);
}
void
@@ -905,24 +945,24 @@ chn_poll(pcm_channel *c, int ev, struct proc *p)
int ret;
s = spltty();
- if (c->direction == PCMDIR_PLAY) {
- /* Fill up the DMA buffer. */
- chn_checkunderflow(c);
- while(chn_wrfeed(c) > 0);
- if (!b->dl) chn_wrintr(c);
- } else {
- /* Suck up the DMA buffer. */
- chn_dmaupdate(c);
- while(chn_rdfeed(c) > 0);
- if (!b->dl) chn_rdintr(c);
+ if (!(c->flags & CHN_F_MAPPED)) {
+ if (c->direction == PCMDIR_PLAY) {
+ /* Fill up the DMA buffer. */
+ chn_checkunderflow(c);
+ while(chn_wrfeed(c) > 0);
+ if (!b->dl) chn_wrintr(c);
+ } else {
+ /* Suck up the DMA buffer. */
+ chn_dmaupdate(c);
+ while(chn_rdfeed(c) > 0);
+ if (!b->dl) chn_rdintr(c);
+ }
}
ret = 0;
if (chn_polltrigger(c) && chn_pollreset(c))
ret = ev;
- else {
+ else
selrecord(p, &bs->sel);
- ret = 0;
- }
splx(s);
return ret;
}
@@ -969,6 +1009,7 @@ chn_flush(pcm_channel *c)
DEB(printf("chn_flush c->flags 0x%08x\n", c->flags));
c->flags |= CHN_F_CLOSING;
+ c->flags &= ~CHN_F_TRIGGERED;
if (c->direction == PCMDIR_REC)
chn_abort(c);
else if (b->dl) {
@@ -988,15 +1029,23 @@ 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) chn_abort(c);
+ if (c->direction == PCMDIR_PLAY && b->dl) chn_abort(c);
return 0;
}
int
chn_reset(pcm_channel *c)
{
+ int r;
+
chn_abort(c);
c->flags &= CHN_F_RESET;
+ r = chn_setblocksize(c, CHN_2NDBUFBLKNUM, CHN_2NDBUFBLKSIZE);
+ if (r)
+ return r;
+ c->format = AFMT_U8;
+ c->speed = 8000;
+ c->volume = (100 << 8) | 100;
chn_resetbuf(c);
c->flags |= CHN_F_INIT;
return 0;
@@ -1025,20 +1074,13 @@ chn_init(pcm_channel *c, void *devinfo, int dir)
c->feeder = &feeder_root;
c->buffer.chan = -1;
c->devinfo = c->init(devinfo, &c->buffer, c, dir);
- if (c->devinfo == NULL)
+ if (c->devinfo == NULL || c->buffer.bufsize == 0)
return 1;
chn_setdir(c, dir);
/* And the secondary buffer. */
- c->blocksize2nd = CHN_2NDBUFBLKSIZE;
- c->fragments = CHN_2NDBUFBLKNUM;
- bs->bufsize = c->blocksize2nd * c->fragments;
- bs->buf = malloc(bs->bufsize, M_DEVBUF, M_NOWAIT);
- if (bs->buf == NULL)
- return 1;
- bzero(bs->buf, bs->bufsize);
- bs->rl = bs->rp = bs->fp = 0;
- bs->fl = bs->bufsize;
+ bs->buf = NULL;
+ bs->bufsize = 0;
return 0;
}
@@ -1094,63 +1136,47 @@ chn_setformat(pcm_channel *c, u_int32_t fmt)
return 0;
}
-/*
- * The seconday buffer is modified only during interrupt.
- * Hence the size of the secondary buffer can be changed
- * at any time as long as an interrupt is disabled.
- */
int
-chn_setblocksize(pcm_channel *c, int blksz)
+chn_setblocksize(pcm_channel *c, int blkcnt, int blksz)
{
snd_dbuf *bs = &c->buffer2nd;
- u_int8_t *tmpbuf;
- int s, tmpbuf_fl, tmpbuf_fp, l;
+ int s, bufsz;
+ if (c->flags & CHN_F_MAPPED) {
+ DEB(printf("chn_setblocksize: can't work on mapped channel"));
+ return EINVAL;
+ }
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 < 2) blksz = c->buffer.sample_size * (c->speed >> 2);
- /* XXX How small can the lower bound be? */
- RANGE(blksz, 64, CHN_2NDBUFWHOLESIZE);
+ /* default to blksz = ~0.25s */
+ if (blksz < 16) blksz = (c->buffer.sample_size * c->speed) >> 2;
+
+ bufsz = blkcnt * blksz;
+ if (blksz < 16 || bufsz > CHN_2NDBUFMAXSIZE)
+ return EINVAL;
- /*
- * Allocate a temporary buffer. It holds the pcm data
- * until the size of the secondary buffer gets changed.
- * bs->buf is not affected, so mmap should work fine.
- */
- tmpbuf = malloc(blksz, M_TEMP, M_NOWAIT);
- if (tmpbuf == NULL) {
- DEB(printf("chn_setblocksize: out of memory."));
- return 1;
- }
- bzero(tmpbuf, blksz);
- tmpbuf_fl = blksz;
- tmpbuf_fp = 0;
s = spltty();
- while (bs->rl > 0 && tmpbuf_fl > 0) {
- l = min(min(bs->rl, bs->bufsize - bs->rp), tmpbuf_fl);
- bcopy(bs->buf + bs->rp, tmpbuf + tmpbuf_fp, l);
- tmpbuf_fl -= l;
- tmpbuf_fp = (tmpbuf_fp + l) % blksz;
- bs->rl -= l;
- bs->fl += l;
- bs->rp = (bs->rp + l) % bs->bufsize;
+ if (bs->buf != NULL)
+ free(bs->buf, M_DEVBUF);
+ bs->buf = malloc(bufsz, M_DEVBUF, M_WAITOK);
+ if (bs->buf == NULL) {
+ splx(s);
+ DEB(printf("chn_setblocksize: out of memory."));
+ return ENOSPC;
}
- /* Change the size of the seconary buffer. */
- bs->bufsize = blksz;
- c->fragments = CHN_2NDBUFBLKNUM;
- c->blocksize2nd = bs->bufsize / c->fragments;
- /* Clear the secondary buffer and restore the pcm data. */
- bzero(bs->buf, bs->bufsize);
- bs->rl = bs->bufsize - tmpbuf_fl;
- bs->rp = 0;
- bs->fl = tmpbuf_fl;
- bs->fp = tmpbuf_fp;
- bcopy(tmpbuf, bs->buf, bs->rl);
-
- free(tmpbuf, M_TEMP);
+ 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);
splx(s);
- return c->blocksize2nd;
+
+ return 0;
}
int
@@ -1164,8 +1190,9 @@ chn_getptr(pcm_channel *c)
{
int hwptr;
int a = (1 << c->align) - 1;
+ snd_dbuf *b = &c->buffer;
- hwptr=c->getptr(c->devinfo);
+ hwptr = b->dl? c->getptr(c->devinfo) : 0;
/* don't allow unaligned values in the hwa ptr */
hwptr &= ~a ; /* Apply channel align mask */
hwptr &= DMA_ALIGN_MASK; /* Apply DMA align mask */
diff --git a/sys/dev/sound/pcm/channel.h b/sys/dev/sound/pcm/channel.h
index dd1ee01..c323fe4 100644
--- a/sys/dev/sound/pcm/channel.h
+++ b/sys/dev/sound/pcm/channel.h
@@ -39,7 +39,7 @@ int chn_reset(pcm_channel *c);
int chn_setvolume(pcm_channel *c, int left, int right);
int chn_setspeed(pcm_channel *c, int speed);
int chn_setformat(pcm_channel *c, u_int32_t fmt);
-int chn_setblocksize(pcm_channel *c, int blksz);
+int chn_setblocksize(pcm_channel *c, int blkcnt, int blksz);
int chn_trigger(pcm_channel *c, int go);
int chn_getptr(pcm_channel *c);
pcmchan_caps *chn_getcaps(pcm_channel *c);
@@ -92,4 +92,4 @@ extern pcm_feeder feeder_root;
/* The total number of blocks per secondary buffer. */
#define CHN_2NDBUFBLKNUM (32)
/* The size of a whole secondary buffer. */
-#define CHN_2NDBUFWHOLESIZE (CHN_2NDBUFBLKSIZE * CHN_2NDBUFBLKNUM)
+#define CHN_2NDBUFMAXSIZE (131072)
diff --git a/sys/dev/sound/pcm/datatypes.h b/sys/dev/sound/pcm/datatypes.h
index 6aba9c2..550d0b7 100644
--- a/sys/dev/sound/pcm/datatypes.h
+++ b/sys/dev/sound/pcm/datatypes.h
@@ -119,17 +119,12 @@ struct _pcm_channel {
u_int32_t speed;
u_int32_t flags;
u_int32_t format, hwfmt;
- u_int32_t blocksize;
- u_int32_t blocksize2nd;
- u_int32_t fragments;
+ u_int32_t blocksize, blocksize2nd;
+ u_int32_t fragments, blocks;
int direction;
- snd_dbuf buffer;
-#define SMEGBUFSZ 4
- u_int8_t smegbuf[SMEGBUFSZ];
- u_int32_t smegcnt;
+ snd_dbuf buffer, buffer2nd;
void *devinfo;
- snd_dbuf buffer2nd;
};
typedef void (pcm_swap_t)(void *data, int dir);
diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c
index 5ad60bd..3ea13a6 100644
--- a/sys/dev/sound/pcm/dsp.c
+++ b/sys/dev/sound/pcm/dsp.c
@@ -130,7 +130,6 @@ dsp_open(snddev_info *d, int chan, int oflags, int devtype)
rdch->volume = (100 << 8) | 100;
rdch->format = fmt;
rdch->speed = DSP_DEFAULT_SPEED;
- rdch->blocksize = 2048;
}
}
if (wrch && (oflags & FWRITE)) {
@@ -140,7 +139,6 @@ dsp_open(snddev_info *d, int chan, int oflags, int devtype)
wrch->volume = (100 << 8) | 100;
wrch->format = fmt;
wrch->speed = DSP_DEFAULT_SPEED;
- wrch->blocksize = 2048;
}
}
return 0;
@@ -160,10 +158,12 @@ dsp_close(snddev_info *d, int chan, int devtype)
if (rdch) {
chn_abort(rdch);
rdch->flags &= ~(CHN_F_BUSY | CHN_F_RUNNING | CHN_F_MAPPED);
+ chn_reset(rdch);
}
if (wrch) {
chn_flush(wrch);
wrch->flags &= ~(CHN_F_BUSY | CHN_F_RUNNING | CHN_F_MAPPED);
+ chn_reset(wrch);
}
d->aplay[chan] = NULL;
d->arec[chan] = NULL;
@@ -222,7 +222,7 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
*/
s = spltty();
switch(cmd) {
-
+#ifdef OLDPCM_IOCTL
/*
* we start with the new ioctl interface.
*/
@@ -317,9 +317,11 @@ 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) {
@@ -343,8 +345,9 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
break ;
case SNDCTL_DSP_SETBLKSIZE:
- if (wrch) chn_setblocksize(wrch, *arg_i);
- if (rdch) chn_setblocksize(rdch, *arg_i);
+ RANGE(*arg_i, 16, 65536);
+ if (wrch) chn_setblocksize(wrch, 2, *arg_i);
+ if (rdch) chn_setblocksize(rdch, 2, *arg_i);
break;
case SNDCTL_DSP_RESET:
@@ -411,32 +414,29 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
/* XXX watch out, this is RW! */
DEB(printf("SNDCTL_DSP_SETFRAGMENT 0x%08x\n", *(int *)arg));
{
- int bytes = 1 << min(*arg_i & 0xffff, 16);
- int count = (*arg_i >> 16) & 0xffff;
pcm_channel *c = wrch? wrch : rdch;
- if (count == 0)
- count = CHN_2NDBUFWHOLESIZE / bytes;
- if (count < 2) {
+ u_int32_t fragln = (*arg_i) & 0x0000ffff;
+ u_int32_t maxfrags = ((*arg_i) & 0xffff0000) >> 16;
+ u_int32_t fragsz;
+
+ RANGE(fragln, 4, 16);
+ fragsz = 1 << fragln;
+
+ if (maxfrags == 0)
+ maxfrags = CHN_2NDBUFMAXSIZE / fragsz;
+ if (maxfrags < 2) {
ret = EINVAL;
break;
}
- if (rdch) {
- chn_setblocksize(rdch, bytes * count);
- rdch->blocksize2nd = bytes;
- rdch->fragments = rdch->buffer2nd.bufsize / rdch->blocksize2nd;
- }
- if (wrch) {
- chn_setblocksize(wrch, bytes * count);
- wrch->blocksize2nd = bytes;
- wrch->fragments = wrch->buffer2nd.bufsize / wrch->blocksize2nd;
- }
+ if (maxfrags * fragsz > CHN_2NDBUFMAXSIZE)
+ maxfrags = CHN_2NDBUFMAXSIZE / fragsz;
- /* eg: 4dwave can only interrupt at buffer midpoint, so
- * it will force blocksize == bufsize/2
- */
- count = c->buffer2nd.bufsize / c->blocksize2nd;
- bytes = ffs(c->blocksize2nd) - 1;
- *arg_i = (count << 16) | bytes;
+ if (rdch)
+ ret = chn_setblocksize(rdch, maxfrags, fragsz);
+ if (wrch && ret == 0)
+ ret = chn_setblocksize(wrch, maxfrags, fragsz);
+
+ *arg_i = (c->fragments << 16) | fragsz;
}
break;
@@ -447,7 +447,7 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
if (rdch) {
snd_dbuf *b = &rdch->buffer;
snd_dbuf *bs = &rdch->buffer2nd;
- if (b->dl)
+ if (b->dl && !(rdch->flags & CHN_F_MAPPED))
/*
* Suck up the secondary and DMA buffer.
* chn_rdfeed*() takes care of the alignment.
@@ -455,7 +455,7 @@ 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 = bs->bufsize / rdch->blocksize2nd;
+ a->fragstotal = rdch->fragments;
a->fragsize = rdch->blocksize2nd;
}
}
@@ -468,7 +468,7 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
if (wrch) {
snd_dbuf *b = &wrch->buffer;
snd_dbuf *bs = &wrch->buffer2nd;
- if (b->dl) {
+ if (b->dl && !(wrch->flags & CHN_F_MAPPED)) {
/*
* Fill up the secondary and DMA buffer.
* chn_wrfeed*() takes care of the alignment.
@@ -479,7 +479,7 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
}
a->bytes = bs->fl;
a->fragments = a->bytes / wrch->blocksize2nd;
- a->fragstotal = bs->bufsize / wrch->blocksize2nd;
+ a->fragstotal = wrch->fragments;
a->fragsize = wrch->blocksize2nd;
}
}
@@ -491,7 +491,7 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
if (rdch) {
snd_dbuf *b = &rdch->buffer;
snd_dbuf *bs = &rdch->buffer2nd;
- if (b->dl)
+ if (b->dl && !(rdch->flags & CHN_F_MAPPED))
/*
* Suck up the secondary and DMA buffer.
* chn_rdfeed*() takes care of the alignment.
@@ -510,7 +510,7 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
if (wrch) {
snd_dbuf *b = &wrch->buffer;
snd_dbuf *bs = &wrch->buffer2nd;
- if (b->dl) {
+ if (b->dl && !(wrch->flags & CHN_F_MAPPED)) {
/*
* Fill up the secondary and DMA buffer.
* chn_wrfeed*() takes care of the alignment.
@@ -520,8 +520,9 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
while (chn_wrfeed(wrch) > 0);
}
a->bytes = bs->total;
- a->blocks = bs->rl / wrch->blocksize2nd;
- a->ptr = bs->fl % wrch->blocksize2nd;
+ a->blocks = wrch->blocks;
+ a->ptr = bs->rp;
+ wrch->blocks = 0;
} else ret = EINVAL;
}
break;
@@ -564,7 +565,8 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
snd_dbuf *b = &wrch->buffer;
if (b->dl) {
chn_checkunderflow(wrch);
- while (chn_wrfeed(wrch) > 0);
+ if (!(wrch->flags & CHN_F_MAPPED))
+ while (chn_wrfeed(wrch) > 0);
}
*arg = b->total;
} else
@@ -613,7 +615,6 @@ dsp_mmap(snddev_info *d, int chan, vm_offset_t offset, int nprot)
if (1 || (wrch && (nprot & PROT_WRITE))) c = wrch;
else if (rdch && (nprot & PROT_READ)) c = rdch;
if (c) {
- printf("dsp_mmap.\n");
c->flags |= CHN_F_MAPPED;
return atop(vtophys(c->buffer2nd.buf + offset));
}
diff --git a/sys/dev/sound/pcm/feeder.c b/sys/dev/sound/pcm/feeder.c
index cc45a5c..5eaf89a 100644
--- a/sys/dev/sound/pcm/feeder.c
+++ b/sys/dev/sound/pcm/feeder.c
@@ -113,11 +113,6 @@ feed_root(pcm_feeder *feeder, pcm_channel *ch, u_int8_t *buffer, u_int32_t count
count &= ~((1 << ch->align) - 1);
KASSERT(count, ("feed_root: aligned count == 0"));
s = spltty();
- if (ch->smegcnt > 0) {
- c = min(ch->smegcnt, count);
- bcopy(ch->smegbuf, buffer, c);
- ch->smegcnt -= c;
- }
count = min(count, stream->uio_resid);
if (count) {
ret = uiomove(buffer, count, stream);
OpenPOWER on IntegriCloud