diff options
Diffstat (limited to 'sys/dev/sound/pcm')
-rw-r--r-- | sys/dev/sound/pcm/buffer.c | 244 | ||||
-rw-r--r-- | sys/dev/sound/pcm/buffer.h | 49 | ||||
-rw-r--r-- | sys/dev/sound/pcm/channel.c | 276 | ||||
-rw-r--r-- | sys/dev/sound/pcm/channel.h | 7 | ||||
-rw-r--r-- | sys/dev/sound/pcm/datatypes.h | 9 | ||||
-rw-r--r-- | sys/dev/sound/pcm/dsp.c | 14 | ||||
-rw-r--r-- | sys/dev/sound/pcm/mixer.c | 4 | ||||
-rw-r--r-- | sys/dev/sound/pcm/sound.h | 1 |
8 files changed, 400 insertions, 204 deletions
diff --git a/sys/dev/sound/pcm/buffer.c b/sys/dev/sound/pcm/buffer.c new file mode 100644 index 0000000..81b4037 --- /dev/null +++ b/sys/dev/sound/pcm/buffer.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <dev/sound/pcm/sound.h> + +static void +sndbuf_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + snd_dbuf *b = (snd_dbuf *)arg; + + if (bootverbose) { + printf("pcm: setmap %lx, %lx; ", (unsigned long)segs->ds_addr, + (unsigned long)segs->ds_len); + printf("%p -> %lx\n", b->buf, (unsigned long)vtophys(b->buf)); + } +} + +/* + * Allocate memory for DMA buffer. If the device do not perform DMA transfer, + * the driver can call malloc(9) by its own. + */ +int +sndbuf_alloc(snd_dbuf *b, bus_dma_tag_t dmatag, int size) +{ + b->dmatag = dmatag; + b->maxsize = size; + b->bufsize = b->maxsize; + if (bus_dmamem_alloc(b->dmatag, (void **)&b->buf, BUS_DMA_NOWAIT, &b->dmamap)) + return ENOSPC; + if (bus_dmamap_load(b->dmatag, b->dmamap, b->buf, b->maxsize, sndbuf_setmap, b, 0)) + return ENOSPC; + return sndbuf_resize(b, 2, b->maxsize / 2); +} + +int +sndbuf_setup(snd_dbuf *b, void *buf, int size) +{ + bzero(b, sizeof(*b)); + b->buf = buf; + b->maxsize = size; + b->bufsize = b->maxsize; + return sndbuf_resize(b, 2, b->maxsize / 2); +} + +void +sndbuf_free(snd_dbuf *b) +{ + bus_dmamap_unload(b->dmatag, b->dmamap); + bus_dmamem_free(b->dmatag, b->buf, b->dmamap); +} + +int +sndbuf_resize(snd_dbuf *b, int blkcnt, int blksz) +{ + if (blkcnt == 0) + blkcnt = b->blkcnt; + if (blksz == 0) + blksz = b->blksz; + if (blkcnt < 2 || blksz < 16 || (blkcnt * blksz > b->maxsize)) + return EINVAL; + b->blkcnt = blkcnt; + b->blksz = blksz; + b->bufsize = blkcnt * blksz; + sndbuf_reset(b); + return 0; +} + +void +sndbuf_clear(snd_dbuf *b, int length) +{ + int i; + u_int16_t data, *p; + + if (length == 0) + return; + + if (b->fmt & AFMT_SIGNED) + data = 0x00; + else + data = 0x80; + + if (b->fmt & AFMT_16BIT) + data <<= 8; + else + data |= data << 8; + + if (b->fmt & AFMT_BIGENDIAN) + data = ((data >> 8) & 0x00ff) | ((data << 8) & 0xff00); + + i = b->fp; + p = (u_int16_t *)(b->buf + b->fp); + while (length > 1) { + *p++ = data; + length -= 2; + i += 2; + if (i >= b->bufsize) { + p = (u_int16_t *)b->buf; + i = 0; + } + } + if (length == 1) + *(b->buf + i) = data & 0xff; +} + +void +sndbuf_reset(snd_dbuf *b) +{ + 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->underflow = 0; + if (b->buf && b->bufsize > 0) + sndbuf_clear(b, b->bufsize); +} + +int +sndbuf_setfmt(snd_dbuf *b, u_int32_t fmt) +{ + b->fmt = fmt; + b->bps = 1; + b->bps <<= (b->fmt & AFMT_STEREO)? 1 : 0; + b->bps <<= (b->fmt & AFMT_16BIT)? 1 : 0; + b->bps <<= (b->fmt & AFMT_32BIT)? 2 : 0; + return 0; +} + +int +sndbuf_getbps(snd_dbuf *b) +{ + return b->bps; +} + +void * +sndbuf_getbuf(snd_dbuf *b) +{ + return b->buf; +} + +int +sndbuf_getsize(snd_dbuf *b) +{ + return b->bufsize; +} + +int +sndbuf_runsz(snd_dbuf *b) +{ + return b->dl; +} + +int +sndbuf_isadmasetup(snd_dbuf *b, struct resource *drq) +{ + /* should do isa_dma_acquire/isa_dma_release here */ + if (drq == NULL) { + b->flags &= ~SNDBUF_F_ISADMA; + b->chan = -1; + } else { + b->flags &= ~SNDBUF_F_ISADMA; + b->chan = rman_get_start(drq); + } + return 0; +} + +int +sndbuf_isadmasetdir(snd_dbuf *b, int dir) +{ + b->dir = (dir == PCMDIR_PLAY)? ISADMA_WRITE : ISADMA_READ; + return 0; +} + +void +sndbuf_isadma(snd_dbuf *b, int go) +{ + KASSERT(b, ("sndbuf_isadma called with b == NULL")); + KASSERT(ISA_DMA(b), ("sndbuf_isadma called on non-ISA channel")); + + switch (go) { + case PCMTRIG_START: + /* isa_dmainit(b->chan, size); */ + isa_dmastart(b->dir | ISADMA_RAW, b->buf, b->bufsize, b->chan); + break; + + case PCMTRIG_STOP: + case PCMTRIG_ABORT: + isa_dmastop(b->chan); + isa_dmadone(b->dir | ISADMA_RAW, b->buf, b->bufsize, b->chan); + break; + } + + DEB(printf("buf 0x%p ISA DMA %s, channel %d\n", + b, + (go == PCMTRIG_START)? "started" : "stopped", + b->chan)); +} + +int +sndbuf_isadmaptr(snd_dbuf *b) +{ + if (ISA_DMA(b)) { + int i = b->dl? isa_dmastatus(b->chan) : b->bufsize; + if (i < 0) + i = 0; + return b->bufsize - i; + } else KASSERT(1, ("sndbuf_isadmaptr called on invalid channel")); + return -1; +} + +void +sndbuf_isadmabounce(snd_dbuf *b) +{ + if (ISA_DMA(b)) { + /* tell isa_dma to bounce data in/out */ + } else + KASSERT(1, ("chn_isadmabounce called on invalid channel")); +} + diff --git a/sys/dev/sound/pcm/buffer.h b/sys/dev/sound/pcm/buffer.h new file mode 100644 index 0000000..62058ce --- /dev/null +++ b/sys/dev/sound/pcm/buffer.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#define ISA_DMA(b) (((b)->chan >= 0 && (b)->chan != 4 && (b)->chan < 8)) + +int sndbuf_alloc(snd_dbuf *b, bus_dma_tag_t dmatag, int size); +int sndbuf_setup(snd_dbuf *b, void *buf, int size); +void sndbuf_free(snd_dbuf *b); +int sndbuf_resize(snd_dbuf *b, int blkcnt, int blksz); +void sndbuf_reset(snd_dbuf *b); +void sndbuf_clear(snd_dbuf *b, int length); +int sndbuf_setfmt(snd_dbuf *b, u_int32_t fmt); +int sndbuf_getbps(snd_dbuf *b); +void *sndbuf_getbuf(snd_dbuf *b); +int sndbuf_getsize(snd_dbuf *b); +int sndbuf_runsz(snd_dbuf *b); + +int sndbuf_isadmasetup(snd_dbuf *b, struct resource *drq); +int sndbuf_isadmasetdir(snd_dbuf *b, int dir); +void sndbuf_isadma(snd_dbuf *b, int go); +int sndbuf_isadmaptr(snd_dbuf *b); +void sndbuf_isadmabounce(snd_dbuf *b); + + diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c index 4030028..da4aa14 100644 --- a/sys/dev/sound/pcm/channel.c +++ b/sys/dev/sound/pcm/channel.c @@ -36,7 +36,6 @@ MALLOC_DEFINE(M_CHANNEL, "channel", "pcm channel"); #define DMA_ALIGN_THRESHOLD 4 #define DMA_ALIGN_MASK (~(DMA_ALIGN_THRESHOLD - 1)) -#define ISA_DMA(b) (((b)->chan >= 0 && (b)->chan != 4 && (b)->chan < 8)) #define CANCHANGE(c) (!(c)->buffer.dl) #define ROUND(x) ((x) & DMA_ALIGN_MASK) @@ -44,7 +43,6 @@ MALLOC_DEFINE(M_CHANNEL, "channel", "pcm channel"); #define DEB(x) x */ -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); @@ -110,14 +108,6 @@ produced on overruns. * gets copied in or out of the real buffer. fix requires mods to isa_dma.c * and possibly fixes to other autodma mode clients */ -static void -chn_isadmabounce(pcm_channel *c) -{ - if (ISA_DMA(&c->buffer)) { - /* tell isa_dma to bounce data in/out */ - } else KASSERT(1, ("chn_isadmabounce called on invalid channel")); -} - static int chn_polltrigger(pcm_channel *c) { @@ -156,7 +146,7 @@ chn_dmadone(pcm_channel *c) else chn_dmaupdate(c); if (ISA_DMA(b)) - chn_isadmabounce(c); /* sync bounce buffer */ + sndbuf_isadmabounce(b); /* sync bounce buffer */ b->int_count++; } @@ -286,7 +276,7 @@ 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, bs->fmt, l); + sndbuf_clear(bs, l); /* Accumulate the total bytes of the moved samples. */ lacc += l; /* A feed to the DMA buffer is equivalent to an interrupt. */ @@ -389,7 +379,7 @@ chn_wrintr(pcm_channel *c) chn_wrfeed(c); else { while (chn_wrfeed(c) > 0); - buf_clear(b, b->fmt, b->fl); + sndbuf_clear(b, b->fl); } chn_dmawakeup(c); if (c->flags & CHN_F_TRIGGERED) { @@ -414,7 +404,7 @@ chn_wrintr(pcm_channel *c) * we are near to underflow condition, so to prevent * audio 'clicks' clear next b->fl bytes */ - buf_clear(b, b->fmt, b->fl); + sndbuf_clear(b, b->fl); if (b->rl < DMA_ALIGN_THRESHOLD) b->underflow = 1; } @@ -423,7 +413,7 @@ chn_wrintr(pcm_channel *c) 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, b->fmt, b->bufsize); + sndbuf_clear(b, b->bufsize); } } } @@ -649,7 +639,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, bs->fmt, l); + sndbuf_clear(bs, l); /* Accumulate the total bytes of the moved samples. */ bs->total += w; wacc += w; @@ -844,76 +834,6 @@ chn_start(pcm_channel *c, int force) return r; } -static void -chn_dma_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) -{ - snd_dbuf *b = (snd_dbuf *)arg; - - if (bootverbose) { - printf("pcm: setmap %lx, %lx; ", (unsigned long)segs->ds_addr, - (unsigned long)segs->ds_len); - printf("%p -> %lx\n", b->buf, (unsigned long)vtophys(b->buf)); - } -} - -/* - * Allocate memory for DMA buffer. If the device do not perform DMA transfer, - * the drvier can call malloc(9) by its own. - */ -int -chn_allocbuf(snd_dbuf *b, bus_dma_tag_t parent_dmat) -{ - b->parent_dmat = parent_dmat; - if (bus_dmamem_alloc(b->parent_dmat, (void **)&b->buf, - BUS_DMA_NOWAIT, &b->dmamap)) return -1; - if (bus_dmamap_load(b->parent_dmat, b->dmamap, b->buf, - b->bufsize, chn_dma_setmap, b, 0)) return -1; - return 0; -} - -void -chn_freebuf(snd_dbuf *b) -{ - bus_dmamem_free(b->parent_dmat, b->buf, b->dmamap); -} - -static void -buf_clear(snd_dbuf *b, u_int32_t fmt, int length) -{ - int i; - u_int16_t data, *p; - - 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); - - i = b->fp; - p = (u_int16_t *)(b->buf + b->fp); - while (length > 1) { - *p++ = data; - length -= 2; - i += 2; - if (i >= b->bufsize) { - p = (u_int16_t *)b->buf; - i = 0; - } - } - if (length == 1) - *(b->buf + i) = data & 0xff; -} - void chn_resetbuf(pcm_channel *c) { @@ -921,59 +841,8 @@ chn_resetbuf(pcm_channel *c) snd_dbuf *bs = &c->buffer2nd; c->blocks = 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->underflow = 0; - if (b->buf && b->bufsize > 0) - 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; - bs->prev_int_count = bs->int_count = 0; - bs->underflow = 0; - if (bs->buf && bs->bufsize > 0) - buf_clear(bs, bs->fmt, bs->bufsize); -} - -void -buf_isadma(snd_dbuf *b, int go) -{ - KASSERT(b, ("buf_isadma called with b == NULL")); - KASSERT(ISA_DMA(b), ("buf_isadma called on non-ISA channel")); - - switch (go) { - case PCMTRIG_START: - isa_dmastart(b->dir | ISADMA_RAW, b->buf, b->bufsize, b->chan); - break; - - case PCMTRIG_STOP: - case PCMTRIG_ABORT: - isa_dmastop(b->chan); - isa_dmadone(b->dir | ISADMA_RAW, b->buf, b->bufsize, b->chan); - break; - } - - DEB(printf("buf 0x%p ISA DMA %s, channel %d\n", - b, - (go == PCMTRIG_START)? "started" : "stopped", - b->chan)); -} - -int -buf_isadmaptr(snd_dbuf *b) -{ - if (ISA_DMA(b)) { - int i = b->dl? isa_dmastatus(b->chan) : b->bufsize; - if (i < 0) - i = 0; - return b->bufsize - i; - } else KASSERT(1, ("buf_isadmaptr called on invalid channel")); - return -1; + sndbuf_reset(b); + sndbuf_reset(bs); } /* @@ -1132,9 +1001,6 @@ chn_reset(pcm_channel *c, u_int32_t fmt) chn_abort(c); c->flags &= CHN_F_RESET; CHANNEL_RESET(c->methods, c->devinfo); - r = chn_setblocksize(c, CHN_2NDBUFBLKNUM, CHN_2NDBUFBLKSIZE); - if (r) - return r; if (fmt) { hwspd = DSP_DEFAULT_SPEED; RANGE(hwspd, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed); @@ -1146,6 +1012,9 @@ chn_reset(pcm_channel *c, u_int32_t fmt) if (r == 0) r = chn_setvolume(c, 100, 100); } + r = chn_setblocksize(c, 0, 0); + if (r) + return r; chn_resetbuf(c); CHANNEL_RESETDONE(c->methods, c->devinfo); /* c->flags |= CHN_F_INIT; */ @@ -1169,6 +1038,7 @@ int chn_init(pcm_channel *c, void *devinfo, int dir) { struct feeder_class *fc; + snd_dbuf *b = &c->buffer; snd_dbuf *bs = &c->buffer2nd; /* Initialize the hardware and DMA buffer first. */ @@ -1191,6 +1061,8 @@ chn_init(pcm_channel *c, void *devinfo, int dir) /* And the secondary buffer. */ bs->buf = NULL; + sndbuf_setfmt(b, AFMT_U8); + sndbuf_setfmt(bs, AFMT_U8); bs->bufsize = 0; return 0; } @@ -1202,7 +1074,7 @@ chn_kill(pcm_channel *c) chn_trigger(c, PCMTRIG_ABORT); while (chn_removefeeder(c) == 0); if (CHANNEL_FREE(c->methods, c->devinfo)) - chn_freebuf(&c->buffer); + sndbuf_free(&c->buffer); c->flags |= CHN_F_DEAD; return 0; } @@ -1236,44 +1108,59 @@ int chn_setspeed(pcm_channel *c, int speed) { pcm_feeder *f; - int r, hwspd, delta; + snd_dbuf *b = &c->buffer; + snd_dbuf *bs = &c->buffer2nd; + int r, delta; DEB(printf("want speed %d, ", speed)); if (speed <= 0) return EINVAL; if (CANCHANGE(c)) { c->speed = speed; - hwspd = speed; - RANGE(hwspd, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed); - DEB(printf("try speed %d, ", hwspd)); - hwspd = CHANNEL_SETSPEED(c->methods, c->devinfo, hwspd); - DEB(printf("got speed %d, ", hwspd)); - delta = hwspd - speed; + b->spd = speed; + bs->spd = speed; + RANGE(b->spd, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed); + DEB(printf("try speed %d, ", b->spd)); + b->spd = CHANNEL_SETSPEED(c->methods, c->devinfo, b->spd); + DEB(printf("got speed %d, ", b->spd)); + + delta = b->spd - bs->spd; if (delta < 0) delta = -delta; + c->feederflags &= ~(1 << FEEDER_RATE); if (delta > 500) c->feederflags |= 1 << FEEDER_RATE; else - speed = hwspd; + bs->spd = b->spd; + r = chn_buildfeeder(c); DEB(printf("r = %d\n", r)); if (r) return r; + + r = chn_setblocksize(c, 0, 0); + if (r) + return r; + if (!(c->feederflags & (1 << FEEDER_RATE))) return 0; + f = chn_findfeeder(c, FEEDER_RATE); DEB(printf("feedrate = %p\n", f)); if (f == NULL) return EINVAL; - r = FEEDER_SET(f, FEEDRATE_SRC, speed); - DEB(printf("feeder_set(FEEDRATE_SRC, %d) = %d\n", speed, r)); + + r = FEEDER_SET(f, FEEDRATE_SRC, bs->spd); + DEB(printf("feeder_set(FEEDRATE_SRC, %d) = %d\n", bs->spd, r)); if (r) return r; - r = FEEDER_SET(f, FEEDRATE_DST, hwspd); - DEB(printf("feeder_set(FEEDRATE_DST, %d) = %d\n", hwspd, r)); + + r = FEEDER_SET(f, FEEDRATE_DST, b->spd); + DEB(printf("feeder_set(FEEDRATE_DST, %d) = %d\n", b->spd, r)); if (r) return r; + return 0; } c->speed = speed; @@ -1287,8 +1174,8 @@ chn_setformat(pcm_channel *c, u_int32_t fmt) snd_dbuf *b = &c->buffer; snd_dbuf *bs = &c->buffer2nd; int r; - u_int32_t hwfmt; + if (CANCHANGE(c)) { DEB(printf("want format %d\n", fmt)); c->format = fmt; @@ -1300,8 +1187,8 @@ chn_setformat(pcm_channel *c, u_int32_t fmt) if (r) return r; hwfmt = c->feeder->desc->out; - b->fmt = hwfmt; - bs->fmt = hwfmt; + sndbuf_setfmt(b, hwfmt); + sndbuf_setfmt(bs, hwfmt); chn_resetbuf(c); CHANNEL_SETFORMAT(c->methods, c->devinfo, hwfmt); return chn_setspeed(c, c->speed); @@ -1316,54 +1203,65 @@ chn_setblocksize(pcm_channel *c, int blkcnt, int blksz) { snd_dbuf *b = &c->buffer; snd_dbuf *bs = &c->buffer2nd; - int s, ss, bufsz; + int s, bufsz, irqhz, tmp; - 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")); + if (!CANCHANGE(c) || (c->flags & CHN_F_MAPPED)) 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) + if (blksz == 0 || blksz == -1) { + if (blksz == -1) + c->flags &= ~CHN_F_HAS_SIZE; + if (c->flags & CHN_F_HAS_SIZE) + return 0; + blksz = (bs->bps * bs->spd) / CHN_DEFAULT_HZ; + tmp = 32; + while (tmp <= blksz) + tmp <<= 1; + tmp >>= 1; + blksz = tmp; + + RANGE(blksz, 16, CHN_2NDBUFMAXSIZE / 2); + RANGE(blkcnt, 2, CHN_2NDBUFMAXSIZE / blksz); + } else { + if ((blksz < 16) || (blkcnt < 2) || (blkcnt * blksz > CHN_2NDBUFMAXSIZE)) + return EINVAL; c->flags |= CHN_F_HAS_SIZE; - /* let us specify blksz without setting CHN_F_HAS_SIZE */ - if (blksz < 0) - blksz = -blksz; - /* default to blksz = ~0.25s */ - if (blksz < 16) - blksz = (ss * c->speed) >> 2; - if (blksz > CHN_2NDBUFMAXSIZE / 2) - blksz = CHN_2NDBUFMAXSIZE / 2; - if (blkcnt < 2) - blkcnt = 2; - - if (blkcnt * blksz > CHN_2NDBUFMAXSIZE) - blkcnt = CHN_2NDBUFMAXSIZE / blksz; + } + bufsz = blkcnt * blksz; s = spltty(); + 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.")); + DEB(printf("chn_setblocksize: out of memory\n")); return ENOSPC; } + bs->bufsize = bufsz; - bs->rl = bs->rp = bs->fp = 0; - bs->fl = bs->bufsize; - buf_clear(bs, bs->fmt, bs->bufsize); bs->blkcnt = blkcnt; bs->blksz = blksz; + + /* adjust for different hw format/speed */ + irqhz = (bs->bps * bs->spd) / bs->blksz; + + b->blksz = (b->bps * b->spd) / irqhz; + + /* round down to 2^x */ + blksz = 32; + while (blksz <= b->blksz) + blksz <<= 1; + blksz >>= 1; + + /* round down to fit hw buffer size */ RANGE(blksz, 16, b->bufsize / 2); + b->blksz = CHANNEL_SETBLOCKSIZE(c->methods, c->devinfo, blksz); + + chn_resetbuf(c); splx(s); return 0; @@ -1439,7 +1337,7 @@ chn_buildfeeder(pcm_channel *c) desc.flags = 0; DEB(printf("find feeder type %d, ", type)); fc = feeder_getclass(&desc); - DEB(printf("got %p\n", f)); + DEB(printf("got %p\n", fc)); if (fc == NULL) return EINVAL; dst = fc->desc->in; @@ -1454,7 +1352,7 @@ chn_buildfeeder(pcm_channel *c) if (chn_addfeeder(c, fc, fc->desc)) return EINVAL; src = fc->desc->out; - DEB(printf("added feeder %p, output %x\n", f, src)); + DEB(printf("added feeder %p, output %x\n", fc, src)); dst = 0; flags &= ~(1 << type); } diff --git a/sys/dev/sound/pcm/channel.h b/sys/dev/sound/pcm/channel.h index 243c207..73c1b8c 100644 --- a/sys/dev/sound/pcm/channel.h +++ b/sys/dev/sound/pcm/channel.h @@ -49,8 +49,6 @@ int chn_getptr(pcm_channel *c); pcmchan_caps *chn_getcaps(pcm_channel *c); u_int32_t chn_getformats(pcm_channel *c); -int chn_allocbuf(snd_dbuf *b, bus_dma_tag_t parent_dmat); -void chn_freebuf(snd_dbuf *b); void chn_resetbuf(pcm_channel *c); void chn_intr(pcm_channel *c); void chn_checkunderflow(pcm_channel *c); @@ -60,9 +58,6 @@ int chn_abort(pcm_channel *c); int fmtvalid(u_int32_t fmt, u_int32_t *fmtlist); -void buf_isadma(snd_dbuf *b, int go); -int buf_isadmaptr(snd_dbuf *b); - #define PCMDIR_PLAY 1 #define PCMDIR_REC -1 @@ -102,4 +97,6 @@ int buf_isadmaptr(snd_dbuf *b); /* The size of a whole secondary buffer. */ #define CHN_2NDBUFMAXSIZE (131072) +#define CHN_DEFAULT_HZ 50 + #define CHANNEL_DECLARE(name) static DEFINE_CLASS(name, name ## _methods, sizeof(struct kobj)) diff --git a/sys/dev/sound/pcm/datatypes.h b/sys/dev/sound/pcm/datatypes.h index aaa17a3..55f4111 100644 --- a/sys/dev/sound/pcm/datatypes.h +++ b/sys/dev/sound/pcm/datatypes.h @@ -57,7 +57,7 @@ struct _snd_mixer { struct _snd_dbuf { u_int8_t *buf; - int bufsize; + int bufsize, maxsize; 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. */ @@ -65,12 +65,15 @@ struct _snd_dbuf { volatile u_int32_t int_count, prev_int_count; volatile u_int32_t total, prev_total; int chan, dir; /* dma channel */ - int fmt, blksz, blkcnt; + int fmt, spd, bps; + int blksz, blkcnt; int underflow, overrun; + u_int32_t flags; bus_dmamap_t dmamap; - bus_dma_tag_t parent_dmat; + bus_dma_tag_t dmatag; struct selinfo sel; }; +#define SNDBUF_F_ISADMA 0x00000001 /*****************************************************************************/ diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c index 59c14e9..9728afd 100644 --- a/sys/dev/sound/pcm/dsp.c +++ b/sys/dev/sound/pcm/dsp.c @@ -240,8 +240,10 @@ 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->buffer2nd.blksz; - if (rdch) p->rec_size = rdch->buffer2nd.blksz; + if (wrch) + p->play_size = wrch->buffer2nd.blksz; + if (rdch) + p->rec_size = rdch->buffer2nd.blksz; } break; @@ -287,14 +289,16 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg) if (rdch && wrch) p->formats |= (d->flags & SD_F_SIMPLEX)? 0 : AFMT_FULLDUPLEX; p->mixers = 1; /* default: one mixer */ - p->inputs = d->mixer->devs; + p->inputs = mix_getdevs(d->mixer); p->left = p->right = 100; } break; case AIOSTOP: - if (*arg_i == AIOSYNC_PLAY && wrch) *arg_i = chn_abort(wrch); - else if (*arg_i == AIOSYNC_CAPTURE && rdch) *arg_i = chn_abort(rdch); + if (*arg_i == AIOSYNC_PLAY && wrch) + *arg_i = chn_abort(wrch); + else if (*arg_i == AIOSYNC_CAPTURE && rdch) + *arg_i = chn_abort(rdch); else { printf("AIOSTOP: bad channel 0x%x\n", *arg_i); *arg_i = 0; diff --git a/sys/dev/sound/pcm/mixer.c b/sys/dev/sound/pcm/mixer.c index ddb161b..22e1d41 100644 --- a/sys/dev/sound/pcm/mixer.c +++ b/sys/dev/sound/pcm/mixer.c @@ -234,11 +234,11 @@ mixer_ioctl(snddev_info *d, u_long cmd, caddr_t arg) case SOUND_MIXER_DEVMASK: case SOUND_MIXER_CAPS: case SOUND_MIXER_STEREODEVS: - v = m->devs; + v = mix_getdevs(m); break; case SOUND_MIXER_RECMASK: - v = m->recdevs; + v = mix_getrecdevs(m); break; case SOUND_MIXER_RECSRC: diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h index 01cdb93..c3e77de 100644 --- a/sys/dev/sound/pcm/sound.h +++ b/sys/dev/sound/pcm/sound.h @@ -81,6 +81,7 @@ struct isa_device { int dummy; }; #include <dev/sound/pcm/datatypes.h> #include <dev/sound/pcm/channel.h> +#include <dev/sound/pcm/buffer.h> #include <dev/sound/pcm/feeder.h> #include <dev/sound/pcm/mixer.h> #include <dev/sound/pcm/dsp.h> |