update code dealing with snd_dbuf objects to do so using a functional interface

modify chn_setblocksize() to pick a default soft-blocksize appropriate to the
sample rate and format in use.  it will aim for a power of two size small
enough to generate block sizes of at most 20ms.  it will also set the
hard-blocksize taking into account rate/format conversions in use.

update drivers to implement setblocksize  correctly:
updated, tested: 	sb16, emu10k1, maestro, solo
updated, untested: 	ad1816, ess, mss, sb8, csa
not updated: 		ds1, es137x, fm801, neomagic, t4dwave, via82c686

i lack hardware to test: ad1816, csa, fm801, neomagic
others will be updated/tested in the next few days.
This commit is contained in:
Cameron Grant 2000-12-23 03:16:13 +00:00
parent 45c27b729e
commit 350a5fafb1
24 changed files with 636 additions and 398 deletions

View File

@ -39,7 +39,7 @@ struct ad1816_chinfo {
struct ad1816_info *parent;
pcm_channel *channel;
snd_dbuf *buffer;
int dir;
int dir, blksz;
};
struct ad1816_info {
@ -131,12 +131,12 @@ ad1816_intr(void *arg)
c &= AD1816_INTRCI | AD1816_INTRPI;
}
/* check for capture interupt */
if (ad1816->rch.buffer->dl && (c & AD1816_INTRCI)) {
if (sndbuf_runsz(ad1816->rch.buffer) && (c & AD1816_INTRCI)) {
chn_intr(ad1816->rch.channel);
served |= AD1816_INTRCI; /* cp served */
}
/* check for playback interupt */
if (ad1816->pch.buffer->dl && (c & AD1816_INTRPI)) {
if (sndbuf_runsz(ad1816->pch.buffer) && (c & AD1816_INTRPI)) {
chn_intr(ad1816->pch.channel);
served |= AD1816_INTRPI; /* pb served */
}
@ -311,8 +311,7 @@ ad1816chan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
ch->parent = ad1816;
ch->channel = c;
ch->buffer = b;
ch->buffer->bufsize = DSP_BUFFSIZE;
if (chn_allocbuf(ch->buffer, ad1816->parent_dmat) == -1) return NULL;
if (sndbuf_alloc(ch->buffer, ad1816->parent_dmat, DSP_BUFFSIZE) == -1) return NULL;
return ch;
}
@ -322,8 +321,7 @@ ad1816chan_setdir(kobj_t obj, void *data, int dir)
struct ad1816_chinfo *ch = data;
struct ad1816_info *ad1816 = ch->parent;
ch->buffer->chan = rman_get_start((dir == PCMDIR_PLAY)?
ad1816->drq1 : ad1816->drq2);
sndbuf_isadmasetup(ch->buffer, (dir == PCMDIR_PLAY)? ad1816->drq1 : ad1816->drq2);
ch->dir = dir;
return 0;
}
@ -384,7 +382,10 @@ ad1816chan_setspeed(kobj_t obj, void *data, u_int32_t speed)
static int
ad1816chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
{
return blocksize;
struct ad1816_chinfo *ch = data;
ch->blksz = blocksize;
return ch->blksz;
}
static int
@ -397,14 +398,14 @@ ad1816chan_trigger(kobj_t obj, void *data, int go)
if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
return 0;
buf_isadma(ch->buffer, go);
sndbuf_isadma(ch->buffer, go);
wr = (ch->dir == PCMDIR_PLAY);
reg = wr? AD1816_PLAY : AD1816_CAPT;
switch (go) {
case PCMTRIG_START:
/* start only if not already running */
if (!(io_rd(ad1816, reg) & AD1816_ENABLE)) {
int cnt = ((ch->buffer->dl) >> 2) - 1;
int cnt = ((ch->blksz) >> 2) - 1;
ad1816_write(ad1816, wr? 8 : 10, cnt); /* count */
ad1816_write(ad1816, wr? 9 : 11, 0); /* reset cur cnt */
ad1816_write(ad1816, 1, ad1816_read(ad1816, 1) |
@ -441,7 +442,7 @@ static int
ad1816chan_getptr(kobj_t obj, void *data)
{
struct ad1816_chinfo *ch = data;
return buf_isadmaptr(ch->buffer);
return sndbuf_isadmaptr(ch->buffer);
}
static pcmchan_caps *

View File

@ -82,7 +82,7 @@ struct ess_chinfo {
pcm_channel *channel;
snd_dbuf *buffer;
int dir, hwch, stopping, run;
u_int32_t fmt, spd;
u_int32_t fmt, spd, blksz;
};
struct ess_info {
@ -358,7 +358,7 @@ ess_intr(void *arg)
printf("ess: play intr while not running\n");
if (sc->pch.stopping) {
sc->pch.run = 0;
buf_isadma(sc->pch.buffer, PCMTRIG_STOP);
sndbuf_isadma(sc->pch.buffer, PCMTRIG_STOP);
sc->pch.stopping = 0;
if (sc->pch.hwch == 1)
ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x01);
@ -373,7 +373,7 @@ ess_intr(void *arg)
printf("ess: record intr while not running\n");
if (sc->rch.stopping) {
sc->rch.run = 0;
buf_isadma(sc->rch.buffer, PCMTRIG_STOP);
sndbuf_isadma(sc->rch.buffer, PCMTRIG_STOP);
sc->rch.stopping = 0;
/* XXX: will this stop audio2? */
ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x01);
@ -509,7 +509,7 @@ ess_start(struct ess_chinfo *ch)
struct ess_info *sc = ch->parent;
int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
ess_setupch(sc, ch->hwch, ch->dir, ch->spd, ch->fmt, ch->buffer->dl);
ess_setupch(sc, ch->hwch, ch->dir, ch->spd, ch->fmt, ch->blksz);
ch->stopping = 0;
if (ch->hwch == 1)
ess_write(sc, 0xb8, ess_read(sc, 0xb8) | 0x01);
@ -547,14 +547,13 @@ esschan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
ch->parent = sc;
ch->channel = c;
ch->buffer = b;
ch->buffer->bufsize = ESS_BUFFSIZE;
if (chn_allocbuf(ch->buffer, sc->parent_dmat) == -1)
if (sndbuf_alloc(ch->buffer, sc->parent_dmat, ESS_BUFFSIZE) == -1)
return NULL;
ch->dir = dir;
ch->hwch = 1;
if ((dir == PCMDIR_PLAY) && (sc->duplex))
ch->hwch = 2;
ch->buffer->chan = rman_get_start((ch->hwch == 1)? sc->drq1 : sc->drq2);
sndbuf_isadmasetup(ch->buffer, (ch->hwch == 1)? sc->drq1 : sc->drq2);
return ch;
}
@ -584,7 +583,10 @@ esschan_setspeed(kobj_t obj, void *data, u_int32_t speed)
static int
esschan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
{
return blocksize;
struct ess_chinfo *ch = data;
ch->blksz = blocksize;
return ch->blksz;
}
static int
@ -598,7 +600,7 @@ esschan_trigger(kobj_t obj, void *data, int go)
switch (go) {
case PCMTRIG_START:
ch->run = 1;
buf_isadma(ch->buffer, go);
sndbuf_isadma(ch->buffer, go);
ess_start(ch);
break;
@ -616,7 +618,7 @@ esschan_getptr(kobj_t obj, void *data)
{
struct ess_chinfo *ch = data;
return buf_isadmaptr(ch->buffer);
return sndbuf_isadmaptr(ch->buffer);
}
static pcmchan_caps *

View File

@ -48,7 +48,7 @@ struct mss_chinfo {
pcm_channel *channel;
snd_dbuf *buffer;
int dir;
u_int32_t fmt;
u_int32_t fmt, blksz;
};
struct mss_info {
@ -67,7 +67,6 @@ struct mss_info {
char mss_indexed_regs[MSS_INDEXED_REGS];
char opl_indexed_regs[OPL_INDEXED_REGS];
int pdma, rdma;
int bd_id; /* used to hold board-id info, eg. sb version,
* mss codec type, etc. etc.
*/
@ -242,19 +241,17 @@ mss_release_resources(struct mss_info *mss, device_t dev)
mss->irq);
mss->irq = 0;
}
if (mss->drq1) {
bus_release_resource(dev, SYS_RES_DRQ, mss->drq1_rid,
mss->drq1);
mss->drq1 = 0;
mss->pdma = -1;
}
if (mss->drq2) {
if (mss->drq2 && mss->drq2 != mss->drq1) {
bus_release_resource(dev, SYS_RES_DRQ, mss->drq2_rid,
mss->drq2);
mss->drq2 = 0;
mss->rdma = -1;
}
if (mss->io_base) {
if (mss->drq1) {
bus_release_resource(dev, SYS_RES_DRQ, mss->drq1_rid,
mss->drq1);
mss->drq1 = 0;
}
if (mss->io_base) {
bus_release_resource(dev, SYS_RES_IOPORT, mss->io_rid,
mss->io_base);
mss->io_base = 0;
@ -274,7 +271,7 @@ mss_release_resources(struct mss_info *mss, device_t dev)
static int
mss_alloc_resources(struct mss_info *mss, device_t dev)
{
int ok = 1;
int pdma, rdma, ok = 1;
if (!mss->io_base)
mss->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, &mss->io_rid,
0, ~0, 1, RF_ACTIVE);
@ -296,16 +293,16 @@ mss_alloc_resources(struct mss_info *mss, device_t dev)
if (mss->drq2_rid >= 0 && !mss->drq2) ok = 0;
if (ok) {
mss->pdma = rman_get_start(mss->drq1);
isa_dma_acquire(mss->pdma);
isa_dmainit(mss->pdma, MSS_BUFFSIZE);
pdma = rman_get_start(mss->drq1);
isa_dma_acquire(pdma);
isa_dmainit(pdma, MSS_BUFFSIZE);
mss->bd_flags &= ~BD_F_DUPLEX;
if (mss->drq2) {
mss->rdma = rman_get_start(mss->drq2);
isa_dma_acquire(mss->rdma);
isa_dmainit(mss->rdma, MSS_BUFFSIZE);
rdma = rman_get_start(mss->drq2);
isa_dma_acquire(rdma);
isa_dmainit(rdma, MSS_BUFFSIZE);
mss->bd_flags |= BD_F_DUPLEX;
} else mss->rdma = mss->pdma;
} else mss->drq2 = mss->drq1;
}
return ok;
}
@ -691,11 +688,11 @@ mss_intr(void *arg)
/* get exact reason for full-duplex boards */
c = FULL_DUPLEX(mss)? ad_read(mss, 24) : 0x30;
c &= ~served;
if (mss->pch.buffer->dl && (c & 0x10)) {
if (sndbuf_runsz(mss->pch.buffer) && (c & 0x10)) {
served |= 0x10;
chn_intr(mss->pch.channel);
}
if (mss->rch.buffer->dl && (c & 0x20)) {
if (sndbuf_runsz(mss->rch.buffer) && (c & 0x20)) {
served |= 0x20;
chn_intr(mss->rch.channel);
}
@ -935,7 +932,7 @@ mss_trigger(struct mss_chinfo *ch, int go)
m = ad_read(mss, 9);
switch (go) {
case PCMTRIG_START:
cnt = (ch->buffer->dl / ss) - 1;
cnt = (ch->blksz / ss) - 1;
DEB(if (m & 4) printf("OUCH! reg 9 0x%02x\n", m););
m |= wr? I9_PEN : I9_CEN; /* enable DMA */
@ -1015,8 +1012,8 @@ opti931_intr(void *arg)
return;
}
if (mss->rch.buffer->dl && (mc11 & 8)) chn_intr(mss->rch.channel);
if (mss->pch.buffer->dl && (mc11 & 4)) chn_intr(mss->pch.channel);
if (sndbuf_runsz(mss->rch.buffer) && (mc11 & 8)) chn_intr(mss->rch.channel);
if (sndbuf_runsz(mss->pch.buffer) && (mc11 & 4)) chn_intr(mss->pch.channel);
opti_wr(mss, 11, ~mc11); /* ack */
if (--loops) goto again;
DEB(printf("xxx too many loops\n");)
@ -1033,10 +1030,9 @@ msschan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
ch->parent = mss;
ch->channel = c;
ch->buffer = b;
ch->buffer->bufsize = MSS_BUFFSIZE;
ch->buffer->chan = (dir == PCMDIR_PLAY)? mss->pdma : mss->rdma;
ch->dir = dir;
if (chn_allocbuf(ch->buffer, mss->parent_dmat) == -1) return NULL;
if (sndbuf_alloc(ch->buffer, mss->parent_dmat, MSS_BUFFSIZE) == -1) return NULL;
sndbuf_isadmasetup(ch->buffer, (dir == PCMDIR_PLAY)? mss->drq1 : mss->drq2);
return ch;
}
@ -1060,7 +1056,10 @@ msschan_setspeed(kobj_t obj, void *data, u_int32_t speed)
static int
msschan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
{
return blocksize;
struct mss_chinfo *ch = data;
ch->blksz = blocksize;
return ch->blksz;
}
static int
@ -1071,7 +1070,7 @@ msschan_trigger(kobj_t obj, void *data, int go)
if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
return 0;
buf_isadma(ch->buffer, go);
sndbuf_isadma(ch->buffer, go);
mss_trigger(ch, go);
return 0;
}
@ -1080,7 +1079,7 @@ static int
msschan_getptr(kobj_t obj, void *data)
{
struct mss_chinfo *ch = data;
return buf_isadmaptr(ch->buffer);
return sndbuf_isadmaptr(ch->buffer);
}
static pcmchan_caps *
@ -1496,11 +1495,13 @@ ymf_test(device_t dev, struct mss_info *mss)
static int
mss_doattach(device_t dev, struct mss_info *mss)
{
int flags = device_get_flags(dev);
int pdma, rdma, flags = device_get_flags(dev);
char status[SND_STATUSLEN];
if (!mss_alloc_resources(mss, dev)) goto no;
mss_init(mss, dev);
pdma = rman_get_start(mss->drq1);
rdma = rman_get_start(mss->drq2);
if (flags & DV_F_TRUE_MSS) {
/* has IRQ/DMA registers, set IRQ and DMA addr */
#ifdef PC98 /* CS423[12] in PC98 can use IRQ3,5,10,12 */
@ -1521,13 +1522,12 @@ mss_doattach(device_t dev, struct mss_info *mss)
if ((io_rd(mss, 3) & 0x40) == 0) device_printf(dev, "IRQ Conflict?\n");
#endif
/* Write IRQ+DMA setup */
if (pdma_bits[mss->pdma] == -1) goto no;
bits |= pdma_bits[mss->pdma];
if (mss->pdma != mss->rdma) {
if (mss->rdma == valid_rdma[mss->pdma]) bits |= 4;
if (pdma_bits[pdma] == -1) goto no;
bits |= pdma_bits[pdma];
if (pdma != rdma) {
if (rdma == valid_rdma[pdma]) bits |= 4;
else {
printf("invalid dual dma config %d:%d\n",
mss->pdma, mss->rdma);
printf("invalid dual dma config %d:%d\n", pdma, rdma);
goto no;
}
}
@ -1542,7 +1542,7 @@ mss_doattach(device_t dev, struct mss_info *mss)
default:
bus_setup_intr(dev, mss->irq, INTR_TYPE_TTY, mss_intr, mss, &mss->ih);
}
if (mss->pdma == mss->rdma)
if (pdma == rdma)
pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX);
if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
/*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
@ -1555,9 +1555,9 @@ mss_doattach(device_t dev, struct mss_info *mss)
goto no;
}
snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %d",
rman_get_start(mss->io_base), rman_get_start(mss->irq), mss->pdma);
if (mss->pdma != mss->rdma) snprintf(status + strlen(status),
SND_STATUSLEN - strlen(status), ":%d", mss->rdma);
rman_get_start(mss->io_base), rman_get_start(mss->irq), pdma);
if (pdma != rdma) snprintf(status + strlen(status),
SND_STATUSLEN - strlen(status), ":%d", rdma);
if (pcm_register(dev, mss, 1, 1)) goto no;
pcm_addchan(dev, PCMDIR_REC, &msschan_class, mss);

View File

@ -84,7 +84,7 @@ struct sb_info {
int bd_id;
u_long bd_flags; /* board-specific flags */
int dl, dh, prio, prio16;
int prio, prio16;
struct sb_chinfo pch, rch;
};
@ -370,15 +370,15 @@ sb16_release_resources(struct sb_info *sb, device_t dev)
bus_release_resource(dev, SYS_RES_IRQ, 0, sb->irq);
sb->irq = 0;
}
if (sb->drq1) {
bus_release_resource(dev, SYS_RES_DRQ, 0, sb->drq1);
sb->drq1 = 0;
}
if (sb->drq2) {
if (sb->drq2 && (sb->drq2 != sb->drq2)) {
bus_release_resource(dev, SYS_RES_DRQ, 1, sb->drq2);
sb->drq2 = 0;
}
if (sb->io_base) {
if (sb->drq1) {
bus_release_resource(dev, SYS_RES_DRQ, 0, sb->drq1);
sb->drq1 = 0;
}
if (sb->io_base) {
bus_release_resource(dev, SYS_RES_IOPORT, 0, sb->io_base);
sb->io_base = 0;
}
@ -419,6 +419,9 @@ sb16_alloc_resources(struct sb_info *sb, device_t dev)
if (sb->drq2) {
isa_dma_acquire(rman_get_start(sb->drq2));
isa_dmainit(rman_get_start(sb->drq2), bs);
} else {
sb->drq2 = sb->drq1;
pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX);
}
return 0;
} else return ENXIO;
@ -458,15 +461,15 @@ sb_intr(void *arg)
}
} else {
if (c & 1) { /* 8-bit dma */
if (sb->pch.dch == sb->dl)
if (sb->pch.dch == 1)
reason |= 1;
if (sb->rch.dch == sb->dl)
if (sb->rch.dch == 1)
reason |= 2;
}
if (c & 2) { /* 16-bit dma */
if (sb->pch.dch == sb->dh)
if (sb->pch.dch == 2)
reason |= 1;
if (sb->rch.dch == sb->dh)
if (sb->rch.dch == 2)
reason |= 2;
}
}
@ -494,38 +497,43 @@ sb_setup(struct sb_info *sb)
int l, pprio;
if (sb->bd_flags & BD_F_DMARUN)
buf_isadma(sb->pch.buffer, PCMTRIG_STOP);
sndbuf_isadma(sb->pch.buffer, PCMTRIG_STOP);
if (sb->bd_flags & BD_F_DMARUN2)
buf_isadma(sb->rch.buffer, PCMTRIG_STOP);
sndbuf_isadma(sb->rch.buffer, PCMTRIG_STOP);
sb->bd_flags &= ~(BD_F_DMARUN | BD_F_DMARUN2);
sb_reset_dsp(sb);
if (sb->bd_flags & BD_F_SB16X) {
pprio = sb->pch.run? 1 : 0;
sb->pch.buffer->chan = pprio? sb->dl : -1;
sb->rch.buffer->chan = pprio? sb->dh : sb->dl;
sndbuf_isadmasetup(sb->pch.buffer, pprio? sb->drq1 : NULL);
sb->pch.dch = pprio? 1 : 0;
sndbuf_isadmasetup(sb->rch.buffer, pprio? sb->drq2 : sb->drq1);
sb->rch.dch = pprio? 2 : 1;
} else {
if (sb->pch.run && sb->rch.run) {
pprio = (sb->rch.fmt & AFMT_16BIT)? 0 : 1;
sb->pch.buffer->chan = pprio? sb->dh : sb->dl;
sb->rch.buffer->chan = pprio? sb->dl : sb->dh;
sndbuf_isadmasetup(sb->pch.buffer, pprio? sb->drq2 : sb->drq1);
sb->pch.dch = pprio? 2 : 1;
sndbuf_isadmasetup(sb->rch.buffer, pprio? sb->drq1 : sb->drq2);
sb->rch.dch = pprio? 1 : 2;
} else {
if (sb->pch.run) {
sb->pch.buffer->chan = (sb->pch.fmt & AFMT_16BIT)? sb->dh : sb->dl;
sb->rch.buffer->chan = (sb->pch.fmt & AFMT_16BIT)? sb->dl : sb->dh;
sndbuf_isadmasetup(sb->pch.buffer, (sb->pch.fmt & AFMT_16BIT)? sb->drq2 : sb->drq1);
sb->pch.dch = (sb->pch.fmt & AFMT_16BIT)? 2 : 1;
sndbuf_isadmasetup(sb->rch.buffer, (sb->pch.fmt & AFMT_16BIT)? sb->drq1 : sb->drq2);
sb->rch.dch = (sb->pch.fmt & AFMT_16BIT)? 1 : 2;
} else if (sb->rch.run) {
sb->pch.buffer->chan = (sb->rch.fmt & AFMT_16BIT)? sb->dl : sb->dh;
sb->rch.buffer->chan = (sb->rch.fmt & AFMT_16BIT)? sb->dh : sb->dl;
sndbuf_isadmasetup(sb->pch.buffer, (sb->rch.fmt & AFMT_16BIT)? sb->drq1 : sb->drq2);
sb->pch.dch = (sb->rch.fmt & AFMT_16BIT)? 1 : 2;
sndbuf_isadmasetup(sb->rch.buffer, (sb->rch.fmt & AFMT_16BIT)? sb->drq2 : sb->drq1);
sb->rch.dch = (sb->rch.fmt & AFMT_16BIT)? 2 : 1;
}
}
}
sb->pch.dch = sb->pch.buffer->chan;
sb->rch.dch = sb->rch.buffer->chan;
sb->pch.buffer->dir = ISADMA_WRITE;
sb->rch.buffer->dir = ISADMA_READ;
sndbuf_isadmasetdir(sb->pch.buffer, PCMDIR_PLAY);
sndbuf_isadmasetdir(sb->rch.buffer, PCMDIR_REC);
/*
printf("setup: [pch = %d, pfmt = %d, pgo = %d] [rch = %d, rfmt = %d, rgo = %d]\n",
@ -553,7 +561,7 @@ sb_setup(struct sb_info *sb)
v = (ch->fmt & AFMT_STEREO)? DSP_F16_STEREO : 0;
v |= (ch->fmt & AFMT_SIGNED)? DSP_F16_SIGNED : 0;
sb_cmd2(sb, v, l);
buf_isadma(ch->buffer, PCMTRIG_START);
sndbuf_isadma(ch->buffer, PCMTRIG_START);
sb->bd_flags |= BD_F_DMARUN;
}
@ -578,7 +586,7 @@ sb_setup(struct sb_info *sb)
v = (ch->fmt & AFMT_STEREO)? DSP_F16_STEREO : 0;
v |= (ch->fmt & AFMT_SIGNED)? DSP_F16_SIGNED : 0;
sb_cmd2(sb, v, l);
buf_isadma(ch->buffer, PCMTRIG_START);
sndbuf_isadma(ch->buffer, PCMTRIG_START);
sb->bd_flags |= BD_F_DMARUN2;
}
@ -595,10 +603,9 @@ sb16chan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
ch->parent = sb;
ch->channel = c;
ch->buffer = b;
ch->buffer->bufsize = SB16_BUFFSIZE;
ch->dir = dir;
if (chn_allocbuf(ch->buffer, sb->parent_dmat) == -1)
if (sndbuf_alloc(ch->buffer, sb->parent_dmat, SB16_BUFFSIZE) == -1)
return NULL;
return ch;
@ -632,7 +639,7 @@ sb16chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
struct sb_chinfo *ch = data;
ch->blksz = blocksize;
return blocksize;
return ch->blksz;
}
static int
@ -659,7 +666,7 @@ sb16chan_getptr(kobj_t obj, void *data)
{
struct sb_chinfo *ch = data;
return buf_isadmaptr(ch->buffer);
return sndbuf_isadmaptr(ch->buffer);
}
static pcmchan_caps *
@ -749,11 +756,9 @@ sb16_attach(device_t dev)
if (bus_setup_intr(dev, sb->irq, INTR_TYPE_TTY, sb_intr, sb, &sb->ih))
goto no;
if (!sb->drq2 || (sb->bd_flags & BD_F_SB16X))
if (sb->bd_flags & BD_F_SB16X)
pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX);
sb->dl = rman_get_start(sb->drq1);
sb->dh = sb->drq2? rman_get_start(sb->drq2) : sb->dl;
sb->prio = 0;
if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
@ -770,7 +775,7 @@ sb16_attach(device_t dev)
snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld",
rman_get_start(sb->io_base), rman_get_start(sb->irq),
rman_get_start(sb->drq1));
if (sb->drq2)
if (!(pcm_getflags(dev) & SD_F_SIMPLEX))
snprintf(status + strlen(status), SND_STATUSLEN - strlen(status),
":%ld", rman_get_start(sb->drq2));

View File

@ -64,7 +64,7 @@ struct sb_chinfo {
pcm_channel *channel;
snd_dbuf *buffer;
int dir;
u_int32_t fmt, spd;
u_int32_t fmt, spd, blksz;
};
struct sb_info {
@ -463,10 +463,10 @@ sb_intr(void *arg)
{
struct sb_info *sb = (struct sb_info *)arg;
if (sb->pch.buffer->dl > 0)
if (sndbuf_runsz(sb->pch.buffer) > 0)
chn_intr(sb->pch.channel);
if (sb->rch.buffer->dl > 0)
if (sndbuf_runsz(sb->rch.buffer) > 0)
chn_intr(sb->rch.channel);
sb_rd(sb, DSP_DATA_AVAIL); /* int ack */
@ -517,7 +517,7 @@ sb_start(struct sb_chinfo *ch)
struct sb_info *sb = ch->parent;
int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
int stereo = (ch->fmt & AFMT_STEREO)? 1 : 0;
int l = ch->buffer->dl;
int l = ch->blksz;
u_char i;
l--;
@ -566,10 +566,9 @@ sbchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
ch->channel = c;
ch->dir = dir;
ch->buffer = b;
ch->buffer->bufsize = SB_BUFFSIZE;
ch->buffer->chan = rman_get_start(sb->drq);
if (chn_allocbuf(ch->buffer, sb->parent_dmat) == -1)
if (sndbuf_alloc(ch->buffer, sb->parent_dmat, SB_BUFFSIZE) == -1)
return NULL;
sndbuf_isadmasetup(ch->buffer, sb->drq);
return ch;
}
@ -594,7 +593,10 @@ sbchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
static int
sbchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
{
return blocksize;
struct sb_chinfo *ch = data;
ch->blksz = blocksize;
return ch->blksz;
}
static int
@ -605,7 +607,7 @@ sbchan_trigger(kobj_t obj, void *data, int go)
if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
return 0;
buf_isadma(ch->buffer, go);
sndbuf_isadma(ch->buffer, go);
if (go == PCMTRIG_START)
sb_start(ch);
else
@ -618,7 +620,7 @@ sbchan_getptr(kobj_t obj, void *data)
{
struct sb_chinfo *ch = data;
return buf_isadmaptr(ch->buffer);
return sndbuf_isadmaptr(ch->buffer);
}
static pcmchan_caps *

View File

@ -242,7 +242,7 @@ au_prepareoutput(struct au_chinfo *ch, u_int32_t format)
{
struct au_info *au = ch->parent;
int i, stereo = (format & AFMT_STEREO)? 1 : 0;
u_int32_t baseaddr = vtophys(ch->buffer->buf);
u_int32_t baseaddr = vtophys(sndbuf_getbuf(ch->buffer));
au_wr(au, 0, 0x1061c, 0, 4);
au_wr(au, 0, 0x10620, 0, 4);
@ -301,9 +301,8 @@ auchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
ch->parent = au;
ch->channel = c;
ch->buffer = b;
ch->buffer->bufsize = AU_BUFFSIZE;
ch->dir = dir;
if (chn_allocbuf(ch->buffer, au->parent_dmat) == -1) return NULL;
if (sndbuf_alloc(ch->buffer, au->parent_dmat, AU_BUFFSIZE) == -1) return NULL;
return ch;
}

View File

@ -523,8 +523,7 @@ csachan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
ch->parent = csa;
ch->channel = c;
ch->buffer = b;
ch->buffer->bufsize = CS461x_BUFFSIZE;
if (chn_allocbuf(ch->buffer, csa->parent_dmat) == -1) return NULL;
if (sndbuf_alloc(ch->buffer, csa->parent_dmat, CS461x_BUFFSIZE) == -1) return NULL;
return ch;
}
@ -538,9 +537,9 @@ csachan_setdir(kobj_t obj, void *data, int dir)
resp = &csa->res;
if (dir == PCMDIR_PLAY)
csa_writemem(resp, BA1_PBA, vtophys(ch->buffer->buf));
csa_writemem(resp, BA1_PBA, vtophys(sndbuf_getbuf(ch->buffer)));
else
csa_writemem(resp, BA1_CBA, vtophys(ch->buffer->buf));
csa_writemem(resp, BA1_CBA, vtophys(sndbuf_getbuf(ch->buffer)));
ch->dir = dir;
return 0;
}
@ -606,12 +605,7 @@ csachan_setspeed(kobj_t obj, void *data, u_int32_t speed)
static int
csachan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
{
#if notdef
return blocksize;
#else
struct csa_chinfo *ch = data;
return ch->buffer->bufsize / 2;
#endif /* notdef */
return CS461x_BUFFSIZE / 2;
}
static int
@ -648,11 +642,11 @@ csachan_getptr(kobj_t obj, void *data)
resp = &csa->res;
if (ch->dir == PCMDIR_PLAY) {
ptr = csa_readmem(resp, BA1_PBA) - vtophys(ch->buffer->buf);
ptr = csa_readmem(resp, BA1_PBA) - vtophys(sndbuf_getbuf(ch->buffer));
if ((ch->fmt & AFMT_U8) != 0 || (ch->fmt & AFMT_S8) != 0)
ptr >>= 1;
} else {
ptr = csa_readmem(resp, BA1_CBA) - vtophys(ch->buffer->buf);
ptr = csa_readmem(resp, BA1_CBA) - vtophys(sndbuf_getbuf(ch->buffer));
if ((ch->fmt & AFMT_U8) != 0 || (ch->fmt & AFMT_S8) != 0)
ptr >>= 1;
}

View File

@ -431,8 +431,8 @@ ds_setuppch(struct sc_pchinfo *ch)
stereo = (ch->fmt & AFMT_STEREO)? 1 : 0;
b16 = (ch->fmt & AFMT_16BIT)? 1 : 0;
c = stereo? 1 : 0;
buf = ch->buffer->buf;
sz = ch->buffer->bufsize;
buf = sndbuf_getbuf(ch->buffer);
sz = sndbuf_getsize(ch->buffer);
ds_initpbank(ch->lslot, c, stereo, b16, ch->spd, buf, sz);
ds_initpbank(ch->lslot + 1, c, stereo, b16, ch->spd, buf, sz);
@ -450,8 +450,8 @@ ds_setuprch(struct sc_rchinfo *ch)
stereo = (ch->fmt & AFMT_STEREO)? 1 : 0;
b16 = (ch->fmt & AFMT_16BIT)? 1 : 0;
buf = ch->buffer->buf;
sz = ch->buffer->bufsize;
buf = sndbuf_getbuf(ch->buffer);
sz = sndbuf_getsize(ch->buffer);
pri = (ch->num == DS1_RECPRIMARY)? 1 : 0;
for (i = 0; i < 2; i++) {
@ -480,14 +480,13 @@ ds1pchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
ch = &sc->pch[sc->pchn++];
ch->buffer = b;
ch->buffer->bufsize = 4096;
ch->parent = sc;
ch->channel = c;
ch->dir = dir;
ch->fmt = AFMT_U8;
ch->spd = 8000;
ch->run = 0;
if (chn_allocbuf(ch->buffer, sc->parent_dmat) == -1)
if (sndbuf_alloc(ch->buffer, sc->parent_dmat, 4096) == -1)
return NULL;
else {
ch->lsnum = sc->pslotfree;
@ -602,13 +601,12 @@ ds1rchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
ch = &sc->rch[sc->rchn];
ch->num = sc->rchn++;
ch->buffer = b;
ch->buffer->bufsize = 4096;
ch->parent = sc;
ch->channel = c;
ch->dir = dir;
ch->fmt = AFMT_U8;
ch->spd = 8000;
if (chn_allocbuf(ch->buffer, sc->parent_dmat) == -1)
if (sndbuf_alloc(ch->buffer, sc->parent_dmat, 4096) == -1)
return NULL;
else {
ch->slot = (ch->num == DS1_RECPRIMARY)? sc->rbank + 2: sc->rbank;

View File

@ -68,7 +68,7 @@ struct sc_info;
/* channel registers */
struct sc_pchinfo {
int spd, fmt, run;
int spd, fmt, blksz, run;
struct emu_voice *master, *slave;
snd_dbuf *buffer;
pcm_channel *channel;
@ -76,7 +76,7 @@ struct sc_pchinfo {
};
struct sc_rchinfo {
int spd, fmt, run, num;
int spd, fmt, run, blksz, num;
u_int32_t idxreg, basereg, sizereg, setupreg, irqmask;
snd_dbuf *buffer;
pcm_channel *channel;
@ -97,7 +97,7 @@ struct sc_info {
int regtype, regid, irqid;
void *ih;
int timer;
int timer, timerinterval;
int pnum, rnum;
struct emu_mem mem;
struct emu_voice voice[64];
@ -302,13 +302,40 @@ emu_enaint(struct sc_info *sc, char channel, int enable)
#endif
/* stuff */
static int
emu_settimer(struct sc_info *sc)
{
struct sc_pchinfo *pch;
struct sc_rchinfo *rch;
int i, tmp, rate;
rate = 0;
for (i = 0; i < EMU_CHANS; i++) {
pch = &sc->pch[i];
tmp = (pch->spd * sndbuf_getbps(pch->buffer)) / pch->blksz;
if (tmp > rate)
rate = tmp;
}
for (i = 0; i < 3; i++) {
rch = &sc->rch[i];
tmp = (rch->spd * sndbuf_getbps(rch->buffer)) / rch->blksz;
if (tmp > rate)
rate = tmp;
}
RANGE(rate, 48, 9600);
sc->timerinterval = 48000 / rate;
emu_wr(sc, TIMER, sc->timerinterval & 0x03ff, 2);
return sc->timerinterval;
}
static int
emu_enatimer(struct sc_info *sc, int go)
{
u_int32_t x;
if (go) {
if (sc->timer++ == 0) {
emu_wr(sc, TIMER, 256, 2);
x = emu_rd(sc, INTE, 4);
x |= INTE_INTERVALTIMERENB;
emu_wr(sc, INTE, x, 4);
@ -430,10 +457,8 @@ emu_vinit(struct sc_info *sc, struct emu_voice *m, struct emu_voice *s,
buf = emu_memalloc(sc, sz);
if (buf == NULL)
return -1;
if (c != NULL) {
c->buffer.buf = buf;
c->buffer.bufsize = sz;
}
if (c != NULL)
sndbuf_setup(&c->buffer, buf, sz);
m->start = emu_memstart(sc, buf) * EMUPAGESIZE;
m->end = m->start + sz;
m->channel = NULL;
@ -631,6 +656,9 @@ emupchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
ch->buffer = b;
ch->parent = sc;
ch->channel = c;
ch->blksz = EMU_BUFFSIZE / 2;
ch->fmt = AFMT_U8;
ch->spd = 8000;
ch->master = emu_valloc(sc);
ch->slave = emu_valloc(sc);
if (emu_vinit(sc, ch->master, ch->slave, EMU_BUFFSIZE, ch->channel))
@ -645,7 +673,7 @@ emupchan_free(kobj_t obj, void *data)
struct sc_pchinfo *ch = data;
struct sc_info *sc = ch->parent;
return emu_memfree(sc, ch->buffer->buf);
return emu_memfree(sc, sndbuf_getbuf(ch->buffer));
}
static int
@ -669,6 +697,14 @@ emupchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
static int
emupchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
{
struct sc_pchinfo *ch = data;
struct sc_info *sc = ch->parent;
int irqrate, blksz;
ch->blksz = blocksize;
emu_settimer(sc);
irqrate = 48000 / sc->timerinterval;
blksz = (ch->spd * sndbuf_getbps(ch->buffer)) / irqrate;
return blocksize;
}
@ -684,6 +720,7 @@ emupchan_trigger(kobj_t obj, void *data, int go)
if (go == PCMTRIG_START) {
emu_vsetup(ch);
emu_vwrite(sc, ch->master);
emu_settimer(sc);
emu_enatimer(sc, 1);
#ifdef EMUDEBUG
printf("start [%d bit, %s, %d hz]\n",
@ -737,9 +774,9 @@ emurchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
KASSERT(dir == PCMDIR_REC, ("emurchan_init: bad direction"));
ch = &sc->rch[sc->rnum];
ch->buffer = b;
ch->buffer->bufsize = EMU_BUFFSIZE;
ch->parent = sc;
ch->channel = c;
ch->blksz = EMU_BUFFSIZE / 2;
ch->fmt = AFMT_U8;
ch->spd = 8000;
ch->num = sc->rnum;
@ -769,10 +806,10 @@ emurchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
break;
}
sc->rnum++;
if (chn_allocbuf(ch->buffer, sc->parent_dmat) == -1)
if (sndbuf_alloc(ch->buffer, sc->parent_dmat, EMU_BUFFSIZE) == -1)
return NULL;
else {
emu_wrptr(sc, 0, ch->basereg, vtophys(ch->buffer->buf));
emu_wrptr(sc, 0, ch->basereg, vtophys(sndbuf_getbuf(ch->buffer)));
emu_wrptr(sc, 0, ch->sizereg, 0); /* off */
return ch;
}
@ -805,6 +842,14 @@ emurchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
static int
emurchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
{
struct sc_rchinfo *ch = data;
struct sc_info *sc = ch->parent;
int irqrate, blksz;
ch->blksz = blocksize;
emu_settimer(sc);
irqrate = 48000 / sc->timerinterval;
blksz = (ch->spd * sndbuf_getbps(ch->buffer)) / irqrate;
return blocksize;
}

View File

@ -253,9 +253,8 @@ eschan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
ch->parent = es;
ch->channel = c;
ch->buffer = b;
ch->buffer->bufsize = ES_BUFFSIZE;
ch->num = ch->parent->num++;
if (chn_allocbuf(ch->buffer, es->parent_dmat) == -1) return NULL;
if (sndbuf_alloc(ch->buffer, es->parent_dmat, ES_BUFFSIZE) == -1) return NULL;
return ch;
}
@ -269,16 +268,16 @@ eschan_setdir(kobj_t obj, void *data, int dir)
bus_space_write_1(es->st, es->sh, ES1370_REG_MEMPAGE,
ES1370_REG_DAC2_FRAMEADR >> 8);
bus_space_write_4(es->st, es->sh, ES1370_REG_DAC2_FRAMEADR & 0xff,
vtophys(ch->buffer->buf));
vtophys(sndbuf_getbuf(ch->buffer)));
bus_space_write_4(es->st, es->sh, ES1370_REG_DAC2_FRAMECNT & 0xff,
(ch->buffer->bufsize >> 2) - 1);
(sndbuf_getsize(ch->buffer) >> 2) - 1);
} else {
bus_space_write_1(es->st, es->sh, ES1370_REG_MEMPAGE,
ES1370_REG_ADC_FRAMEADR >> 8);
bus_space_write_4(es->st, es->sh, ES1370_REG_ADC_FRAMEADR & 0xff,
vtophys(ch->buffer->buf));
vtophys(sndbuf_getbuf(ch->buffer)));
bus_space_write_4(es->st, es->sh, ES1370_REG_ADC_FRAMECNT & 0xff,
(ch->buffer->bufsize >> 2) - 1);
(sndbuf_getsize(ch->buffer) >> 2) - 1);
}
ch->dir = dir;
return 0;
@ -346,10 +345,7 @@ eschan_trigger(kobj_t obj, void *data, int go)
if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
return 0;
ss = 1;
ss <<= (ch->fmt & AFMT_STEREO)? 1 : 0;
ss <<= (ch->fmt & AFMT_16BIT)? 1 : 0;
cnt = ch->buffer->dl / ss - 1;
cnt = (sndbuf_runsz(ch->buffer) / sndbuf_getbps(ch->buffer)) - 1;
if (ch->dir == PCMDIR_PLAY) {
if (go == PCMTRIG_START) {
@ -366,7 +362,7 @@ eschan_trigger(kobj_t obj, void *data, int go)
ES1370_REG_DAC2_FRAMECNT >> 8);
bus_space_write_4(es->st, es->sh,
ES1370_REG_DAC2_FRAMECNT & 0xff,
(ch->buffer->bufsize >> 2) - 1);
(sndbuf_getsize(ch->buffer) >> 2) - 1);
} else es->ctrl &= ~CTRL_DAC2_EN;
} else {
if (go == PCMTRIG_START) {
@ -380,7 +376,7 @@ eschan_trigger(kobj_t obj, void *data, int go)
ES1370_REG_ADC_FRAMECNT >> 8);
bus_space_write_4(es->st, es->sh,
ES1370_REG_ADC_FRAMECNT & 0xff,
(ch->buffer->bufsize >> 2) - 1);
(sndbuf_getsize(ch->buffer) >> 2) - 1);
} else es->ctrl &= ~CTRL_ADC_EN;
}
bus_space_write_4(es->st, es->sh, ES1370_REG_SERIAL_CONTROL, es->sctrl);

View File

@ -331,9 +331,8 @@ fm801ch_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
ch->parent = fm801;
ch->channel = c;
ch->buffer = b;
ch->buffer->bufsize = FM801_BUFFSIZE;
ch->dir = dir;
if( chn_allocbuf(ch->buffer, fm801->parent_dmat) == -1) return NULL;
if (sndbuf_alloc(ch->buffer, fm801->parent_dmat, FM801_BUFFSIZE) == -1) return NULL;
return (void *)ch;
}
@ -435,7 +434,7 @@ fm801ch_trigger(kobj_t obj, void *data, int go)
{
struct fm801_chinfo *ch = data;
struct fm801_info *fm801 = ch->parent;
u_int32_t baseaddr = vtophys(ch->buffer->buf);
u_int32_t baseaddr = vtophys(sndbuf_getbuf(ch->buffer));
snd_dbuf *b = ch->buffer;
u_int32_t k1;

View File

@ -85,6 +85,7 @@ struct agg_chinfo {
snd_dbuf *buffer;
bus_addr_t offset;
u_int32_t blocksize;
u_int32_t speed;
int dir;
u_int num;
u_int16_t aputype;
@ -518,9 +519,9 @@ aggch_start_dac(struct agg_chinfo *ch)
{
u_int wpwa = APU_USE_SYSMEM | (ch->offset >> 9);
u_int size = AGG_BUFSIZ >> 1;
u_int speed = ch->channel->speed;
u_int speed = ch->speed;
u_int offset = ch->offset >> 1;
u_int cp = ch->buffer->rp >> 1;
u_int cp = 0;
u_int16_t apuch = ch->num << 1;
u_int dv;
int pan = 0;
@ -613,7 +614,7 @@ calc_timer_freq(struct agg_chinfo *ch)
if (ch->aputype == APUTYPE_8BITLINEAR)
ss >>= 1;
return (ch->channel->speed * ss + ch->blocksize - 1) / ch->blocksize;
return (ch->speed * ss) / ch->blocksize;
}
static void
@ -641,6 +642,7 @@ aggch_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
struct agg_info *ess = devinfo;
struct agg_chinfo *ch;
bus_addr_t physaddr;
void *p;
ch = (dir == PCMDIR_PLAY)? ess->pch + ess->playchns : &ess->rch;
@ -650,9 +652,10 @@ aggch_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
ch->num = ess->playchns;
ch->dir = dir;
b->buf = dma_malloc(ess, AGG_BUFSIZ, &physaddr);
if (b->buf == NULL)
p = dma_malloc(ess, AGG_BUFSIZ, &physaddr);
if (p == NULL)
return NULL;
sndbuf_setup(b, p, AGG_BUFSIZ);
ch->offset = physaddr - ess->baseaddr;
if (physaddr < ess->baseaddr || ch->offset > WPWA_MAXADDR) {
@ -663,7 +666,6 @@ aggch_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
return NULL;
}
b->bufsize = AGG_BUFSIZ;
ch->wcreg_tpl = (physaddr - 16) & WAVCACHE_CHCTL_ADDRTAG_MASK;
if (dir == PCMDIR_PLAY) {
@ -683,7 +685,7 @@ aggch_free(kobj_t obj, void *data)
struct agg_info *ess = ch->parent;
/* free up buffer - called after channel stopped */
dma_free(ess, ch->buffer->buf);
dma_free(ess, sndbuf_getbuf(ch->buffer));
/* return 0 if ok */
return 0;
@ -719,7 +721,10 @@ aggch_setplayformat(kobj_t obj, void *data, u_int32_t format)
static int
aggch_setspeed(kobj_t obj, void *data, u_int32_t speed)
{
return speed;
struct agg_chinfo *ch = data;
ch->speed = speed;
return ch->speed;
}
static int

View File

@ -338,8 +338,7 @@ nmchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
chnbuf = (dir == PCMDIR_PLAY)? sc->pbuf : sc->rbuf;
ch = (dir == PCMDIR_PLAY)? &sc->pch : &sc->rch;
ch->buffer = b;
ch->buffer->bufsize = NM_BUFFSIZE;
ch->buffer->buf = (u_int8_t *)rman_get_virtual(sc->buf) + chnbuf;
sndbuf_setup(ch->buffer, (u_int8_t *)rman_get_virtual(sc->buf) + chnbuf, NM_BUFFSIZE);
if (bootverbose)
device_printf(sc->dev, "%s buf %p\n", (dir == PCMDIR_PLAY)?
"play" : "rec", ch->buffer->buf);

View File

@ -80,7 +80,7 @@ struct ess_chinfo {
pcm_channel *channel;
snd_dbuf *buffer;
int dir, hwch, stopping;
u_int32_t fmt, spd;
u_int32_t fmt, spd, blksz;
};
struct ess_info {
@ -477,7 +477,7 @@ ess_start(struct ess_chinfo *ch)
struct ess_info *sc = ch->parent;
DEB(printf("ess_start\n"););
ess_setupch(sc, ch->hwch, ch->dir, ch->spd, ch->fmt, ch->buffer->dl);
ess_setupch(sc, ch->hwch, ch->dir, ch->spd, ch->fmt, ch->blksz);
ch->stopping = 0;
if (ch->hwch == 1) {
ess_write(sc, 0xb8, ess_read(sc, 0xb8) | 0x01);
@ -519,9 +519,8 @@ esschan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
ch->parent = sc;
ch->channel = c;
ch->buffer = b;
ch->buffer->bufsize = ESS_BUFFSIZE;
ch->dir = dir;
if (chn_allocbuf(ch->buffer, sc->parent_dmat) == -1)
if (sndbuf_alloc(ch->buffer, sc->parent_dmat, ESS_BUFFSIZE) == -1)
return NULL;
ch->hwch = 1;
if ((dir == PCMDIR_PLAY) && (sc->duplex))
@ -555,7 +554,10 @@ esschan_setspeed(kobj_t obj, void *data, u_int32_t speed)
static int
esschan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
{
return blocksize;
struct ess_chinfo *ch = data;
ch->blksz = blocksize;
return ch->blksz;
}
static int
@ -570,7 +572,7 @@ esschan_trigger(kobj_t obj, void *data, int go)
switch (go) {
case PCMTRIG_START:
ess_dmasetup(sc, ch->hwch, vtophys(ch->buffer->buf), ch->buffer->bufsize, ch->dir);
ess_dmasetup(sc, ch->hwch, vtophys(sndbuf_getbuf(ch->buffer)), sndbuf_getsize(ch->buffer), ch->dir);
ess_dmatrigger(sc, ch->hwch, 1);
ess_start(ch);
break;
@ -780,7 +782,7 @@ ess_dmapos(struct ess_info *sc, int ch)
i, p);
i = port_rd(sc->vc, 0x4, 2) + 1;
p = port_rd(sc->vc, 0x4, 2) + 1;
} while ((p > sc->dmasz[ch -1 ] || i < p || (p - i) > 0x8) && j++ < 1000);
} while ((p > sc->dmasz[ch - 1] || i < p || (p - i) > 0x8) && j++ < 1000);
ess_dmatrigger(sc, ch, 1);
}
else if (ch == 2)

View File

@ -52,7 +52,7 @@ struct tr_chinfo {
u_int32_t eso, delta;
u_int32_t rvol, cvol;
u_int32_t gvsel, pan, vol, ctrl;
int index, ss;
int index;
snd_dbuf *buffer;
pcm_channel *channel;
struct tr_info *parent;
@ -391,10 +391,9 @@ trchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
ch->index = -1;
}
ch->buffer = b;
ch->buffer->bufsize = TR_BUFFSIZE;
ch->parent = tr;
ch->channel = c;
if (chn_allocbuf(ch->buffer, tr->parent_dmat) == -1) return NULL;
if (sndbuf_alloc(ch->buffer, tr->parent_dmat, TR_BUFFSIZE) == -1) return NULL;
else return ch;
}
@ -405,9 +404,9 @@ trchan_setdir(kobj_t obj, void *data, int dir)
struct tr_info *tr = ch->parent;
if (dir == PCMDIR_PLAY && ch->index >= 0) {
ch->fmc = ch->fms = ch->ec = ch->alpha = 0;
ch->lba = vtophys(ch->buffer->buf);
ch->lba = vtophys(sndbuf_getbuf(ch->buffer));
ch->cso = 0;
ch->eso = ch->buffer->bufsize - 1;
ch->eso = sndbuf_getsize(ch->buffer) - 1;
ch->rvol = ch->cvol = 0;
ch->gvsel = 0;
ch->pan = 0;
@ -423,10 +422,10 @@ trchan_setdir(kobj_t obj, void *data, int dir)
i = tr_rd(tr, TR_REG_DMAR11, 1) & 0x03;
tr_wr(tr, TR_REG_DMAR11, i | 0x54, 1);
/* set up base address */
tr_wr(tr, TR_REG_DMAR0, vtophys(ch->buffer->buf), 4);
tr_wr(tr, TR_REG_DMAR0, vtophys(sndbuf_getbuf(ch->buffer)), 4);
/* set up buffer size */
i = tr_rd(tr, TR_REG_DMAR4, 4) & ~0x00ffffff;
tr_wr(tr, TR_REG_DMAR4, i | (ch->buffer->bufsize - 1), 4);
tr_wr(tr, TR_REG_DMAR4, i | (sndbuf_getsize(ch->buffer) - 1), 4);
} else return -1;
return 0;
}
@ -438,12 +437,9 @@ trchan_setformat(kobj_t obj, void *data, u_int32_t format)
struct tr_info *tr = ch->parent;
u_int32_t bits = tr_fmttobits(format);
ch->ss = 1;
ch->ss <<= (format & AFMT_STEREO)? 1 : 0;
ch->ss <<= (format & AFMT_16BIT)? 1 : 0;
if (ch->index >= 0) {
tr_rdch(tr, ch->index, ch);
ch->eso = (ch->buffer->bufsize / ch->ss) - 1;
ch->eso = (sndbuf_getsize(ch->buffer) / sndbuf_getbps(ch->buffer)) - 1;
ch->ctrl = bits | 0x01;
tr_wrch(tr, ch->index, ch);
} else {
@ -482,7 +478,7 @@ static int
trchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
{
struct tr_chinfo *ch = data;
return ch->buffer->bufsize / 2;
return sndbuf_getsize(ch->buffer) / 2;
}
static int
@ -516,8 +512,8 @@ trchan_getptr(kobj_t obj, void *data)
if (ch->index >= 0) {
tr_rdch(tr, ch->index, ch);
return ch->cso * ch->ss;
} else return tr_rd(tr, TR_REG_DMAR0, 4) - vtophys(ch->buffer->buf);
return ch->cso * sndbuf_getbps(ch->buffer);
} else return tr_rd(tr, TR_REG_DMAR0, 4) - vtophys(sndbuf_getbuf(ch->buffer));
}
static pcmchan_caps *

View File

@ -217,9 +217,8 @@ viachan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
ch->parent = via;
ch->channel = c;
ch->buffer = b;
b->bufsize = VIA_BUFFSIZE;
if (chn_allocbuf(ch->buffer, via->parent_dmat) == -1) return NULL;
if (sndbuf_alloc(ch->buffer, via->parent_dmat, VIA_BUFFSIZE) == -1) return NULL;
return ch;
}
@ -240,14 +239,14 @@ viachan_setdir(kobj_t obj, void *data, int dir)
* is feeding.
*/
ado = via->sgd_table;
chunk_size = ch->buffer->bufsize / SEGS_PER_CHAN;
chunk_size = sndbuf_getsize(ch->buffer) / SEGS_PER_CHAN;
if (dir == PCMDIR_REC) {
ado += SEGS_PER_CHAN;
}
DEB(printf("SGD table located at va %p\n", ado));
phys_addr = vtophys(ch->buffer->buf);
phys_addr = vtophys(sndbuf_getbuf(ch->buffer));
for (i = 0; i < SEGS_PER_CHAN; i++) {
ado->ptr = phys_addr;
flag = (i == SEGS_PER_CHAN-1) ?
@ -339,7 +338,7 @@ viachan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
{
struct via_chinfo *ch = data;
return ch->buffer->bufsize / 2;
return sndbuf_getsize(ch->buffer) / 2;
}
static int
@ -409,7 +408,7 @@ DEB(printf("viachan_getptr: len / base = %x / %x\n", len, base));
if (seg == 0) seg = SEGS_PER_CHAN;
/* Now work out offset: seg less count */
ptr = seg * ch->buffer->bufsize / SEGS_PER_CHAN - len;
ptr = seg * sndbuf_getsize(ch->buffer) / SEGS_PER_CHAN - len;
DEB(printf("return ptr=%d\n", ptr));
return ptr;
}
@ -430,7 +429,7 @@ DEB(printf("viachan_getptr: len / base = %x / %x\n", len, base));
if (seg == 0) seg = SEGS_PER_CHAN;
/* Now work out offset: seg less count */
ptr = seg * ch->buffer->bufsize / SEGS_PER_CHAN - len;
ptr = seg * sndbuf_getsize(ch->buffer) / SEGS_PER_CHAN - len;
/* DMA appears to operate on memory 'lines' of 32 bytes */
/* so don't return any part line - it isn't in RAM yet */

244
sys/dev/sound/pcm/buffer.c Normal file
View File

@ -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"));
}

View File

@ -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);

View File

@ -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 == 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;
if (blksz >= 2)
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);
}

View File

@ -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))

View File

@ -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
/*****************************************************************************/

View File

@ -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;

View File

@ -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:

View File

@ -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>