diff options
| author | Cameron Grant <cg@FreeBSD.org> | 2000-05-26 21:55:13 +0000 |
|---|---|---|
| committer | Cameron Grant <cg@FreeBSD.org> | 2000-05-26 21:55:13 +0000 |
| commit | d28089a10d16493efc7e5a2fb775576e8f47fd66 (patch) | |
| tree | 578f56ffc7bb0277b7a6829d7ecc56b07aa0f7be /sys/dev | |
| parent | 04553e63a5a58711ea8510a970d6e754f3348e75 (diff) | |
Notes
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/sound/pcm/channel.c | 284 | ||||
| -rw-r--r-- | sys/dev/sound/pcm/datatypes.h | 17 | ||||
| -rw-r--r-- | sys/dev/sound/pcm/dsp.c | 81 |
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; } |
