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