summaryrefslogtreecommitdiffstats
path: root/sys/dev/sound/pcm
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/sound/pcm')
-rw-r--r--sys/dev/sound/pcm/buffer.c244
-rw-r--r--sys/dev/sound/pcm/buffer.h49
-rw-r--r--sys/dev/sound/pcm/channel.c276
-rw-r--r--sys/dev/sound/pcm/channel.h7
-rw-r--r--sys/dev/sound/pcm/datatypes.h9
-rw-r--r--sys/dev/sound/pcm/dsp.c14
-rw-r--r--sys/dev/sound/pcm/mixer.c4
-rw-r--r--sys/dev/sound/pcm/sound.h1
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>
OpenPOWER on IntegriCloud