summaryrefslogtreecommitdiffstats
path: root/sys/dev/sound/pci/emu10k1.c
diff options
context:
space:
mode:
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