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:
parent
45c27b729e
commit
350a5fafb1
@ -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 *
|
||||
|
@ -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 *
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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 *
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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 *
|
||||
|
@ -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
244
sys/dev/sound/pcm/buffer.c
Normal 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"));
|
||||
}
|
||||
|
49
sys/dev/sound/pcm/buffer.h
Normal file
49
sys/dev/sound/pcm/buffer.h
Normal 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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user