diff options
author | cg <cg@FreeBSD.org> | 2001-03-24 23:10:29 +0000 |
---|---|---|
committer | cg <cg@FreeBSD.org> | 2001-03-24 23:10:29 +0000 |
commit | 11442775804b9679c2c761846072b171d2507840 (patch) | |
tree | 2c8e61a99c9323312c5656a92269f975ac6b0c12 /sys/dev/sound/pci/emu10k1.c | |
parent | fb291ae7e5515cf63d4544d3eeff0a4c791e3cad (diff) | |
download | FreeBSD-src-11442775804b9679c2c761846072b171d2507840.zip FreeBSD-src-11442775804b9679c2c761846072b171d2507840.tar.gz |
mega-commit.
this introduces a new buffering mechanism which results in dramatic
simplification of the channel manager.
as several structures have changed, we take the opportunity to move their
definitions into the source files where they are used, make them private and
de-typedef them.
the sound drivers are updated to use snd_setup_intr instead of
bus_setup_intr, and to comply with the de-typedefed structures.
the ac97, mixer and channel layers have been updated with finegrained
locking, as have some drivers- not all though. the rest will follow soon.
Diffstat (limited to 'sys/dev/sound/pci/emu10k1.c')
-rw-r--r-- | sys/dev/sound/pci/emu10k1.c | 116 |
1 files changed, 56 insertions, 60 deletions
diff --git a/sys/dev/sound/pci/emu10k1.c b/sys/dev/sound/pci/emu10k1.c index e816572..388a8e7 100644 --- a/sys/dev/sound/pci/emu10k1.c +++ b/sys/dev/sound/pci/emu10k1.c @@ -61,7 +61,7 @@ struct emu_voice { int start, end, vol; u_int32_t buf; struct emu_voice *slave; - pcm_channel *channel; + struct pcm_channel *channel; }; struct sc_info; @@ -70,16 +70,16 @@ struct sc_info; struct sc_pchinfo { int spd, fmt, blksz, run; struct emu_voice *master, *slave; - snd_dbuf *buffer; - pcm_channel *channel; + struct snd_dbuf *buffer; + struct pcm_channel *channel; struct sc_info *parent; }; struct sc_rchinfo { int spd, fmt, run, blksz, num; u_int32_t idxreg, basereg, sizereg, setupreg, irqmask; - snd_dbuf *buffer; - pcm_channel *channel; + struct snd_dbuf *buffer; + struct pcm_channel *channel; struct sc_info *parent; }; @@ -96,6 +96,7 @@ struct sc_info { struct resource *reg, *irq; int regtype, regid, irqid; void *ih; + void *lock; int timer, timerinterval; int pnum, rnum; @@ -144,7 +145,7 @@ static u_int32_t emu_rfmt_efx[] = { 0 }; -static pcmchan_caps emu_reccaps[3] = { +static struct pcmchan_caps emu_reccaps[3] = { {8000, 48000, emu_rfmt_ac97, 0}, {8000, 8000, emu_rfmt_mic, 0}, {48000, 48000, emu_rfmt_efx, 0}, @@ -158,7 +159,7 @@ static u_int32_t emu_pfmt[] = { 0 }; -static pcmchan_caps emu_playcaps = {4000, 48000, emu_pfmt, 0}; +static struct pcmchan_caps emu_playcaps = {4000, 48000, emu_pfmt, 0}; static int adcspeed[8] = {48000, 44100, 32000, 24000, 22050, 16000, 11025, 8000}; @@ -239,6 +240,7 @@ emu_wrefx(struct sc_info *sc, unsigned int pc, unsigned int data) /* -------------------------------------------------------------------- */ /* ac97 codec */ +/* no locking needed */ static int emu_rdcd(kobj_t obj, void *devinfo, int regno) @@ -267,40 +269,6 @@ static kobj_method_t emu_ac97_methods[] = { AC97_DECLARE(emu_ac97); /* -------------------------------------------------------------------- */ - -#if 0 -/* playback channel interrupts */ -static u_int32_t -emu_testint(struct sc_info *sc, char channel) -{ - int reg = (channel & 0x20)? CLIPH : CLIPL; - channel &= 0x1f; - reg |= 1 << 24; - reg |= channel << 16; - return emu_rdptr(sc, 0, reg); -} - -static void -emu_clrint(struct sc_info *sc, char channel) -{ - int reg = (channel & 0x20)? CLIPH : CLIPL; - channel &= 0x1f; - reg |= 1 << 24; - reg |= channel << 16; - emu_wrptr(sc, 0, reg, 1); -} - -static void -emu_enaint(struct sc_info *sc, char channel, int enable) -{ - int reg = (channel & 0x20)? CLIEH : CLIEL; - channel &= 0x1f; - reg |= 1 << 24; - reg |= channel << 16; - emu_wrptr(sc, 0, reg, enable); -} -#endif - /* stuff */ static int emu_settimer(struct sc_info *sc) @@ -450,15 +418,15 @@ emu_valloc(struct sc_info *sc) static int emu_vinit(struct sc_info *sc, struct emu_voice *m, struct emu_voice *s, - u_int32_t sz, pcm_channel *c) + u_int32_t sz, struct snd_dbuf *b) { void *buf; buf = emu_memalloc(sc, sz); if (buf == NULL) return -1; - if (c != NULL) - sndbuf_setup(&c->buffer, buf, sz); + if (b != NULL) + sndbuf_setup(b, buf, sz); m->start = emu_memstart(sc, buf) * EMUPAGESIZE; m->end = m->start + sz; m->channel = NULL; @@ -646,10 +614,11 @@ emu_vdump(struct sc_info *sc, struct emu_voice *v) /* channel interface */ static void * -emupchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +emupchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct sc_info *sc = devinfo; struct sc_pchinfo *ch; + void *r; KASSERT(dir == PCMDIR_PLAY, ("emupchan_init: bad direction")); ch = &sc->pch[sc->pnum++]; @@ -659,12 +628,13 @@ emupchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) ch->blksz = EMU_BUFFSIZE / 2; ch->fmt = AFMT_U8; ch->spd = 8000; + snd_mtxlock(sc->lock); ch->master = emu_valloc(sc); ch->slave = emu_valloc(sc); - if (emu_vinit(sc, ch->master, ch->slave, EMU_BUFFSIZE, ch->channel)) - return NULL; - else - return ch; + r = (emu_vinit(sc, ch->master, ch->slave, EMU_BUFFSIZE, ch->buffer))? NULL : ch; + snd_mtxunlock(sc->lock); + + return r; } static int @@ -672,8 +642,13 @@ emupchan_free(kobj_t obj, void *data) { struct sc_pchinfo *ch = data; struct sc_info *sc = ch->parent; + int r; + + snd_mtxlock(sc->lock); + r = emu_memfree(sc, sndbuf_getbuf(ch->buffer)); + snd_mtxunlock(sc->lock); - return emu_memfree(sc, sndbuf_getbuf(ch->buffer)); + return r; } static int @@ -702,8 +677,10 @@ emupchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) int irqrate, blksz; ch->blksz = blocksize; + snd_mtxlock(sc->lock); emu_settimer(sc); irqrate = 48000 / sc->timerinterval; + snd_mtxunlock(sc->lock); blksz = (ch->spd * sndbuf_getbps(ch->buffer)) / irqrate; return blocksize; } @@ -717,6 +694,7 @@ emupchan_trigger(kobj_t obj, void *data, int go) if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) return 0; + snd_mtxlock(sc->lock); if (go == PCMTRIG_START) { emu_vsetup(ch); emu_vwrite(sc, ch->master); @@ -733,6 +711,7 @@ emupchan_trigger(kobj_t obj, void *data, int go) } ch->run = (go == PCMTRIG_START)? 1 : 0; emu_vtrigger(sc, ch->master, ch->run); + snd_mtxunlock(sc->lock); return 0; } @@ -741,11 +720,16 @@ emupchan_getptr(kobj_t obj, void *data) { struct sc_pchinfo *ch = data; struct sc_info *sc = ch->parent; + int r; + + snd_mtxlock(sc->lock); + r = emu_vpos(sc, ch->master); + snd_mtxunlock(sc->lock); - return emu_vpos(sc, ch->master); + return r; } -static pcmchan_caps * +static struct pcmchan_caps * emupchan_getcaps(kobj_t obj, void *data) { return &emu_playcaps; @@ -766,7 +750,7 @@ CHANNEL_DECLARE(emupchan); /* channel interface */ static void * -emurchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +emurchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { struct sc_info *sc = devinfo; struct sc_rchinfo *ch; @@ -809,8 +793,10 @@ emurchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) if (sndbuf_alloc(ch->buffer, sc->parent_dmat, EMU_BUFFSIZE) == -1) return NULL; else { + snd_mtxlock(sc->lock); emu_wrptr(sc, 0, ch->basereg, vtophys(sndbuf_getbuf(ch->buffer))); emu_wrptr(sc, 0, ch->sizereg, 0); /* off */ + snd_mtxunlock(sc->lock); return ch; } } @@ -847,8 +833,10 @@ emurchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) int irqrate, blksz; ch->blksz = blocksize; + snd_mtxlock(sc->lock); emu_settimer(sc); irqrate = 48000 / sc->timerinterval; + snd_mtxunlock(sc->lock); blksz = (ch->spd * sndbuf_getbps(ch->buffer)) / irqrate; return blocksize; } @@ -861,6 +849,7 @@ emurchan_trigger(kobj_t obj, void *data, int go) struct sc_info *sc = ch->parent; u_int32_t val; + snd_mtxlock(sc->lock); switch(go) { case PCMTRIG_START: ch->run = 1; @@ -893,6 +882,7 @@ emurchan_trigger(kobj_t obj, void *data, int go) default: break; } + snd_mtxunlock(sc->lock); return 0; } @@ -902,11 +892,16 @@ emurchan_getptr(kobj_t obj, void *data) { struct sc_rchinfo *ch = data; struct sc_info *sc = ch->parent; + int r; + + snd_mtxlock(sc->lock); + r = emu_rdptr(sc, 0, ch->idxreg) & 0x0000ffff; + snd_mtxunlock(sc->lock); - return emu_rdptr(sc, 0, ch->idxreg) & 0x0000ffff; + return r; } -static pcmchan_caps * +static struct pcmchan_caps * emurchan_getcaps(kobj_t obj, void *data) { struct sc_rchinfo *ch = data; @@ -1421,12 +1416,12 @@ emu_pci_attach(device_t dev) int i, mapped; char status[SND_STATUSLEN]; - if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT)) == NULL) { + if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO)) == NULL) { device_printf(dev, "cannot allocate softc\n"); return ENXIO; } - bzero(sc, sizeof(*sc)); + sc->lock = snd_mtxcreate(device_get_nameunit(dev)); sc->dev = dev; sc->type = pci_get_devid(dev); sc->rev = pci_get_revid(dev); @@ -1482,8 +1477,7 @@ emu_pci_attach(device_t dev) sc->irqid = 0; sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irqid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); - if (!sc->irq || - bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, emu_intr, sc, &sc->ih)) { + if (!sc->irq || snd_setup_intr(dev, sc->irq, INTR_MPSAFE, emu_intr, sc, &sc->ih)) { device_printf(dev, "unable to map interrupt\n"); goto bad; } @@ -1508,6 +1502,7 @@ bad: if (sc->ih) bus_teardown_intr(dev, sc->irq, sc->ih); if (sc->irq) bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); if (sc->parent_dmat) bus_dma_tag_destroy(sc->parent_dmat); + if (sc->lock) snd_mtxfree(sc->lock); free(sc, M_DEVBUF); return ENXIO; } @@ -1530,6 +1525,7 @@ emu_pci_detach(device_t dev) bus_teardown_intr(dev, sc->irq, sc->ih); bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); bus_dma_tag_destroy(sc->parent_dmat); + snd_mtxfree(sc->lock); free(sc, M_DEVBUF); return 0; @@ -1548,7 +1544,7 @@ static device_method_t emu_methods[] = { static driver_t emu_driver = { "pcm", emu_methods, - sizeof(snddev_info), + sizeof(struct snddev_info), }; static devclass_t pcm_devclass; |