summaryrefslogtreecommitdiffstats
path: root/sys/dev/sound/pci/emu10k1.c
diff options
context:
space:
mode:
authorcg <cg@FreeBSD.org>2001-03-24 23:10:29 +0000
committercg <cg@FreeBSD.org>2001-03-24 23:10:29 +0000
commit11442775804b9679c2c761846072b171d2507840 (patch)
tree2c8e61a99c9323312c5656a92269f975ac6b0c12 /sys/dev/sound/pci/emu10k1.c
parentfb291ae7e5515cf63d4544d3eeff0a4c791e3cad (diff)
downloadFreeBSD-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.c116
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;
OpenPOWER on IntegriCloud