From 149d70c6671fe30f0ed2a0e3ebf80de1d9450c5a Mon Sep 17 00:00:00 2001 From: nwhitehorn Date: Sat, 7 Feb 2009 01:15:13 +0000 Subject: Rearrange this code slightly to pass softcs around instead of device_t, solving a possible panic when snd_ai2s is loaded at boot time. Also change the device setup to indicate to the pcm layer that the device is MPSAFE. Submitted by: Marco Trillo Suggestions by: Ariff Abdullah --- sys/dev/sound/macio/aoa.c | 25 +++++++++++------- sys/dev/sound/macio/aoa.h | 7 ++--- sys/dev/sound/macio/davbus.c | 9 +++---- sys/dev/sound/macio/i2s.c | 22 +++++++--------- sys/dev/sound/macio/snapper.c | 18 +++++++++++++ sys/dev/sound/macio/tumbler.c | 61 +++++++++++++++++++++++++------------------ 6 files changed, 85 insertions(+), 57 deletions(-) diff --git a/sys/dev/sound/macio/aoa.c b/sys/dev/sound/macio/aoa.c index cd90d7f..54efe4f 100644 --- a/sys/dev/sound/macio/aoa.c +++ b/sys/dev/sound/macio/aoa.c @@ -104,13 +104,14 @@ aoa_dma_set_program(struct aoa_dma *dma) #define AOA_BUFFER_SIZE 65536 static struct aoa_dma * -aoa_dma_create(device_t self) +aoa_dma_create(struct aoa_softc *sc) { - struct aoa_softc *sc = pcm_getdevinfo(self); struct aoa_dma *dma; bus_dma_tag_t tag; int err; + device_t self; + self = sc->sc_dev; err = bus_dma_tag_create(bus_get_dma_tag(self), 4, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, AOA_BUFFER_SIZE, 1, AOA_BUFFER_SIZE, 0, NULL, NULL, &tag); @@ -214,14 +215,13 @@ static void * aoa_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) { - device_t self = devinfo; - struct aoa_softc *sc = pcm_getdevinfo(self); + struct aoa_softc *sc = devinfo; struct aoa_dma *dma; int max_slots, err; KASSERT(dir == PCMDIR_PLAY, ("bad dir")); - dma = aoa_dma_create(self); + dma = aoa_dma_create(sc); if (!dma) return (NULL); dma->pcm = c; @@ -230,7 +230,7 @@ aoa_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, /* One slot per block, plus branch to 0 plus STOP. */ max_slots = 2 + dma->bufsz / dma->blksz; - err = dbdma_allocate_channel(dma->reg, 0, bus_get_dma_tag(self), + err = dbdma_allocate_channel(dma->reg, 0, bus_get_dma_tag(sc->sc_dev), max_slots, &dma->channel ); if (err != 0) { aoa_dma_delete(dma); @@ -308,9 +308,9 @@ aoa_chan_free(kobj_t obj, void *data) } void -aoa_interrupt(void *arg) +aoa_interrupt(void *xsc) { - struct aoa_softc *sc = arg; + struct aoa_softc *sc = xsc; struct aoa_dma *dma; if (!(dma = sc->sc_intrp) || !dma->running) @@ -357,11 +357,16 @@ static kobj_method_t aoa_chan_methods[] = { CHANNEL_DECLARE(aoa_chan); int -aoa_attach(device_t self, void *sc) +aoa_attach(void *xsc) { char status[SND_STATUSLEN]; + struct aoa_softc *sc; + device_t self; int err; + sc = xsc; + self = sc->sc_dev; + if (pcm_register(self, sc, 1, 0)) return (ENXIO); @@ -369,7 +374,7 @@ aoa_attach(device_t self, void *sc) AOA_BUFFER_SIZE); DPRINTF(("pcm_getbuffersize returned %d\n", err)); - pcm_addchan(self, PCMDIR_PLAY, &aoa_chan_class, self); + pcm_addchan(self, PCMDIR_PLAY, &aoa_chan_class, sc); snprintf(status, sizeof(status), "at %s", ofw_bus_get_name(self)); pcm_setstatus(self, status); diff --git a/sys/dev/sound/macio/aoa.h b/sys/dev/sound/macio/aoa.h index c216731..285ae51 100644 --- a/sys/dev/sound/macio/aoa.h +++ b/sys/dev/sound/macio/aoa.h @@ -35,12 +35,13 @@ #endif struct aoa_softc { - void *sc_intrp; - struct resource *sc_odma; + device_t sc_dev; + void *sc_intrp; + struct resource *sc_odma; }; void aoa_interrupt(void *); -int aoa_attach(device_t, void *sc); +int aoa_attach(void *xsc); #endif /* SOUND_AOA_H */ diff --git a/sys/dev/sound/macio/davbus.c b/sys/dev/sound/macio/davbus.c index 9729178..15909f8 100644 --- a/sys/dev/sound/macio/davbus.c +++ b/sys/dev/sound/macio/davbus.c @@ -52,7 +52,6 @@ struct davbus_softc { struct aoa_softc aoa; - device_t dev; phandle_t node; phandle_t soundnode; struct resource *reg; @@ -497,7 +496,7 @@ davbus_attach(device_t self) sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); - sc->dev = self; + sc->aoa.sc_dev = self; sc->node = ofw_bus_get_node(self); sc->soundnode = OF_child(sc->node); @@ -529,8 +528,8 @@ davbus_attach(device_t self) if (err != 0) return (err); - bus_setup_intr(self, dbdma_irq, INTR_TYPE_AV | INTR_MPSAFE, - NULL, aoa_interrupt, sc, &cookie); + snd_setup_intr(self, dbdma_irq, INTR_MPSAFE, aoa_interrupt, + sc, &cookie); /* Now initialize the controller. */ @@ -555,7 +554,7 @@ davbus_attach(device_t self) DAVBUS_OUTPUT_SUBFRAME0 | DAVBUS_RATE_44100 | DAVBUS_INTR_PORTCHG); /* Attach DBDMA engine and PCM layer */ - err = aoa_attach(self,sc); + err = aoa_attach(sc); if (err) return (err); diff --git a/sys/dev/sound/macio/i2s.c b/sys/dev/sound/macio/i2s.c index 47943a0..11a0826 100644 --- a/sys/dev/sound/macio/i2s.c +++ b/sys/dev/sound/macio/i2s.c @@ -78,7 +78,6 @@ struct i2s_softc { struct aoa_softc aoa; - device_t dev; phandle_t node; phandle_t soundnode; struct resource *reg; @@ -179,7 +178,7 @@ i2s_attach(device_t self) sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); - sc->dev = self; + sc->aoa.sc_dev = self; sc->node = ofw_bus_get_node(self); port = of_find_firstchild_byname(sc->node, "i2s-a"); @@ -216,8 +215,8 @@ i2s_attach(device_t self) if (err != 0) return (err); - bus_setup_intr(self, dbdma_irq, INTR_TYPE_AV | INTR_MPSAFE, NULL, - aoa_interrupt, sc, &dbdma_ih); + snd_setup_intr(self, dbdma_irq, INTR_MPSAFE, aoa_interrupt, + sc, &dbdma_ih); oirq = rman_get_start(dbdma_irq); err = powerpc_config_intr(oirq, INTR_TRIGGER_EDGE, INTR_POLARITY_LOW); @@ -233,12 +232,12 @@ i2s_attach(device_t self) return (ENOMEM); i2s_delayed_attach->ich_func = i2s_postattach; - i2s_delayed_attach->ich_arg = self; + i2s_delayed_attach->ich_arg = sc; if (config_intrhook_establish(i2s_delayed_attach) != 0) return (ENOMEM); - return (aoa_attach(self,sc)); + return (aoa_attach(sc)); } /***************************************************************************** @@ -717,16 +716,13 @@ i2s_set_outputs(void *ptr, u_int mask) } static void -i2s_postattach(void *arg) +i2s_postattach(void *xsc) { - device_t self = arg; - struct i2s_softc *sc; + struct i2s_softc *sc = xsc; + device_t self; int i; - KASSERT(self != NULL, ("bad arg")); - KASSERT(i2s_delayed_attach != NULL, ("bogus call")); - - sc = pcm_getdevinfo(self); + self = sc->aoa.sc_dev; /* Reset the codec. */ i2s_audio_hw_reset(sc); diff --git a/sys/dev/sound/macio/snapper.c b/sys/dev/sound/macio/snapper.c index 4bd4d61..8acca10 100644 --- a/sys/dev/sound/macio/snapper.c +++ b/sys/dev/sound/macio/snapper.c @@ -433,10 +433,14 @@ static int snapper_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) { struct snapper_softc *sc; + struct mtx *mixer_lock; + int locked; u_int l, r; u_char reg[6]; sc = device_get_softc(mix_getdevinfo(m)); + mixer_lock = mixer_get_lock(m); + locked = mtx_owned(mixer_lock); if (left > 100 || right > 100) return (0); @@ -452,8 +456,22 @@ snapper_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) reg[3] = (r & 0xff0000) >> 16; reg[4] = (r & 0x00ff00) >> 8; reg[5] = r & 0x0000ff; + + /* + * We need to unlock the mixer lock because iicbus_transfer() + * may sleep. The mixer lock itself is unnecessary here + * because it is meant to serialize hardware access, which + * is taken care of by the I2C layer, so this is safe. + */ + + if (locked) + mtx_unlock(mixer_lock); + snapper_write(sc, SNAPPER_VOLUME, reg); + if (locked) + mtx_lock(mixer_lock); + return (left | (right << 8)); } diff --git a/sys/dev/sound/macio/tumbler.c b/sys/dev/sound/macio/tumbler.c index 600a929..3007ece 100644 --- a/sys/dev/sound/macio/tumbler.c +++ b/sys/dev/sound/macio/tumbler.c @@ -95,8 +95,6 @@ static int tumbler_reinit(struct snd_mixer *m); static int tumbler_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right); static int tumbler_setrecsrc(struct snd_mixer *m, u_int32_t src); -static int tumbler_set_volume(struct tumbler_softc *sc, int left, - int right); static device_method_t tumbler_methods[] = { /* Device interface. */ @@ -381,12 +379,46 @@ static int tumbler_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) { struct tumbler_softc *sc; + struct mtx *mixer_lock; + int locked; + u_int l, r; + u_char reg[6]; sc = device_get_softc(mix_getdevinfo(m)); + mixer_lock = mixer_get_lock(m); + locked = mtx_owned(mixer_lock); switch (dev) { case SOUND_MIXER_VOLUME: - return (tumbler_set_volume(sc, left, right)); + if (left > 100 || right > 100) + return (0); + + l = (left == 0 ? 0 : tumbler_volume_table[left - 1]); + r = (right == 0 ? 0 : tumbler_volume_table[right - 1]); + + reg[0] = (l & 0xff0000) >> 16; + reg[1] = (l & 0x00ff00) >> 8; + reg[2] = l & 0x0000ff; + reg[3] = (r & 0xff0000) >> 16; + reg[4] = (r & 0x00ff00) >> 8; + reg[5] = r & 0x0000ff; + + /* + * We need to unlock the mixer lock because iicbus_transfer() + * may sleep. The mixer lock itself is unnecessary here + * because it is meant to serialize hardware access, which + * is taken care of by the I2C layer, so this is safe. + */ + + if (locked) + mtx_unlock(mixer_lock); + + tumbler_write(sc, TUMBLER_VOLUME, reg); + + if (locked) + mtx_lock(mixer_lock); + + return (left | (right << 8)); } return (0); @@ -398,26 +430,3 @@ tumbler_setrecsrc(struct snd_mixer *m, u_int32_t src) return (0); } -static int -tumbler_set_volume(struct tumbler_softc *sc, int left, int right) -{ - u_int l, r; - u_char reg[6]; - - if (left > 100 || right > 100) - return (0); - - l = (left == 0 ? 0 : tumbler_volume_table[left - 1]); - r = (right == 0 ? 0 : tumbler_volume_table[right - 1]); - - reg[0] = (l & 0xff0000) >> 16; - reg[1] = (l & 0x00ff00) >> 8; - reg[2] = l & 0x0000ff; - reg[3] = (r & 0xff0000) >> 16; - reg[4] = (r & 0x00ff00) >> 8; - reg[5] = r & 0x0000ff; - tumbler_write(sc, TUMBLER_VOLUME, reg); - - return (left | (right << 8)); -} - -- cgit v1.1