diff options
author | netchild <netchild@FreeBSD.org> | 2005-07-31 11:01:13 +0000 |
---|---|---|
committer | netchild <netchild@FreeBSD.org> | 2005-07-31 11:01:13 +0000 |
commit | 24f05a42fb8ffb125b0a887f8cda4aec81af4611 (patch) | |
tree | 04e4a4598cfd56940d9f573f52731eec5bdfcbba /sys/dev/sound | |
parent | b3a4958eb7b757b4d5be9b22d1a916f2a37b24ee (diff) | |
download | FreeBSD-src-24f05a42fb8ffb125b0a887f8cda4aec81af4611.zip FreeBSD-src-24f05a42fb8ffb125b0a887f8cda4aec81af4611.tar.gz |
* als4000 can't do 48k properly (perhaps it really can't at all!).
Set maxspeed to 44.1k instead.
* Add locking / MPSAFE
* Fix recording
Submitted by: Ariff Abdullah <skywizard@MyBSD.org.my>
Diffstat (limited to 'sys/dev/sound')
-rw-r--r-- | sys/dev/sound/pci/als4000.c | 79 |
1 files changed, 70 insertions, 9 deletions
diff --git a/sys/dev/sound/pci/als4000.c b/sys/dev/sound/pci/als4000.c index a7ebac1..0dbfa51 100644 --- a/sys/dev/sound/pci/als4000.c +++ b/sys/dev/sound/pci/als4000.c @@ -75,6 +75,7 @@ struct sc_info { struct resource *reg, *irq; int regid, irqid; void *ih; + struct mtx *lock; unsigned int bufsz; struct sc_chinfo pch, rch; @@ -90,7 +91,11 @@ static u_int32_t als_format[] = { 0 }; -static struct pcmchan_caps als_caps = { 4000, 48000, als_format, 0 }; +/* + * I don't believe this rotten soundcard can do 48k, really, + * trust me. + */ +static struct pcmchan_caps als_caps = { 4000, 44100, als_format, 0 }; /* ------------------------------------------------------------------------- */ /* Register Utilities */ @@ -199,6 +204,7 @@ alschan_init(kobj_t obj, void *devinfo, struct sc_info *sc = devinfo; struct sc_chinfo *ch; + snd_mtxlock(sc->lock); if (dir == PCMDIR_PLAY) { ch = &sc->pch; ch->gcr_fifo_status = ALS_GCR_FIFO0_STATUS; @@ -214,8 +220,10 @@ alschan_init(kobj_t obj, void *devinfo, ch->speed = DSP_DEFAULT_SPEED; ch->buffer = b; if (sndbuf_alloc(ch->buffer, sc->parent_dmat, sc->bufsz) != 0) { + snd_mtxunlock(sc->lock); return NULL; } + snd_mtxunlock(sc->lock); return ch; } @@ -223,8 +231,11 @@ static int alschan_setformat(kobj_t obj, void *data, u_int32_t format) { struct sc_chinfo *ch = data; + struct sc_info *sc = ch->parent; + snd_mtxlock(sc->lock); ch->format = format; + snd_mtxunlock(sc->lock); return 0; } @@ -234,15 +245,18 @@ alschan_setspeed(kobj_t obj, void *data, u_int32_t speed) struct sc_chinfo *ch = data, *other; struct sc_info *sc = ch->parent; + snd_mtxlock(sc->lock); other = (ch->dir == PCMDIR_PLAY) ? &sc->rch : &sc->pch; /* Deny request if other dma channel is active */ if (other->dma_active) { ch->speed = other->speed; + snd_mtxunlock(sc->lock); return other->speed; } ch->speed = speed; + snd_mtxunlock(sc->lock); return speed; } @@ -263,10 +277,13 @@ static int alschan_getptr(kobj_t obj, void *data) { struct sc_chinfo *ch = data; + struct sc_info *sc = ch->parent; int32_t pos, sz; + snd_mtxlock(sc->lock); pos = als_gcr_rd(ch->parent, ch->gcr_fifo_status) & 0xffff; sz = sndbuf_getsize(ch->buffer); + snd_mtxunlock(sc->lock); return (2 * sz - pos - 1) % sz; } @@ -378,7 +395,9 @@ static int alspchan_trigger(kobj_t obj, void *data, int go) { struct sc_chinfo *ch = data; + struct sc_info *sc = ch->parent; + snd_mtxlock(sc->lock); switch(go) { case PCMTRIG_START: als_playback_start(ch); @@ -387,6 +406,7 @@ alspchan_trigger(kobj_t obj, void *data, int go) als_playback_stop(ch); break; } + snd_mtxunlock(sc->lock); return 0; } @@ -468,7 +488,9 @@ static int alsrchan_trigger(kobj_t obj, void *data, int go) { struct sc_chinfo *ch = data; + struct sc_info *sc = ch->parent; + snd_mtxlock(sc->lock); switch(go) { case PCMTRIG_START: als_capture_start(ch); @@ -477,6 +499,7 @@ alsrchan_trigger(kobj_t obj, void *data, int go) als_capture_stop(ch); break; } + snd_mtxunlock(sc->lock); return 0; } @@ -574,7 +597,7 @@ static int alsmix_setrecsrc(struct snd_mixer *m, u_int32_t src) { struct sc_info *sc = mix_getdevinfo(m); - u_int32_t i, l, r; + u_int32_t i, l, r, mask; for (i = l = r = 0; i < SOUND_MIXER_NRDEVICES; i++) { if (src & (1 << i)) { @@ -583,8 +606,24 @@ alsmix_setrecsrc(struct snd_mixer *m, u_int32_t src) } } - als_mix_wr(sc, SB16_IMASK_L, l); - als_mix_wr(sc, SB16_IMASK_R, r); + /* ALS mixer is really an SB16 mixer */ + + mask = 0; + + if (src & SOUND_MASK_MIC) + mask |= 0x01; + + if (src & SOUND_MASK_CD) + mask |= 0x06; + + if (src & SOUND_MASK_LINE) + mask |= 0x18; + + if (src & SOUND_MASK_SYNTH) + mask |= 0x60; + + als_mix_wr(sc, SB16_IMASK_L, l|mask); + als_mix_wr(sc, SB16_IMASK_R, r|mask); return src; } @@ -605,13 +644,20 @@ als_intr(void *p) struct sc_info *sc = (struct sc_info *)p; u_int8_t intr, sb_status; + snd_mtxlock(sc->lock); intr = als_intr_rd(sc); - if (intr & 0x80) + if (intr & 0x80) { + snd_mtxunlock(sc->lock); chn_intr(sc->pch.channel); + snd_mtxlock(sc->lock); + } - if (intr & 0x40) + if (intr & 0x40) { + snd_mtxunlock(sc->lock); chn_intr(sc->rch.channel); + snd_mtxlock(sc->lock); + } /* ACK interrupt in PCI core */ als_intr_wr(sc, intr); @@ -627,6 +673,8 @@ als_intr(void *p) als_ack_read(sc, ALS_MIDI_DATA); if (sb_status & ALS_IRQ_CR1E) als_ack_read(sc, ALS_CR1E_ACK_PORT); + + snd_mtxunlock(sc->lock); return; } @@ -708,6 +756,10 @@ als_resource_free(device_t dev, struct sc_info *sc) bus_dma_tag_destroy(sc->parent_dmat); sc->parent_dmat = 0; } + if (sc->lock) { + snd_mtxfree(sc->lock); + sc->lock = NULL; + } } static int @@ -730,7 +782,7 @@ als_resource_grab(device_t dev, struct sc_info *sc) goto bad; } - if (bus_setup_intr(dev, sc->irq, INTR_TYPE_AV, als_intr, + if (snd_setup_intr(dev, sc->irq, INTR_MPSAFE, als_intr, sc, &sc->ih)) { device_printf(dev, "unable to setup interrupt\n"); goto bad; @@ -745,8 +797,8 @@ als_resource_grab(device_t dev, struct sc_info *sc) /*filter*/NULL, /*filterarg*/NULL, /*maxsize*/sc->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff, - /*flags*/0, /*lockfunc*/busdma_lock_mutex, - /*lockarg*/&Giant, &sc->parent_dmat) != 0) { + /*flags*/0, /*lockfunc*/NULL, + /*lockarg*/NULL, &sc->parent_dmat) != 0) { device_printf(dev, "unable to create dma tag\n"); goto bad; } @@ -768,6 +820,7 @@ als_pci_attach(device_t dev) return ENXIO; } + sc->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc"); sc->dev = dev; data = pci_read_config(dev, PCIR_COMMAND, 2); @@ -851,9 +904,11 @@ als_pci_suspend(device_t dev) { struct sc_info *sc = pcm_getdevinfo(dev); + snd_mtxlock(sc->lock); sc->pch.dma_was_active = als_playback_stop(&sc->pch); sc->rch.dma_was_active = als_capture_stop(&sc->rch); als_uninit(sc); + snd_mtxunlock(sc->lock); return 0; } @@ -862,13 +917,17 @@ als_pci_resume(device_t dev) { struct sc_info *sc = pcm_getdevinfo(dev); + snd_mtxlock(sc->lock); + if (als_init(sc) != 0) { device_printf(dev, "unable to reinitialize the card\n"); + snd_mtxunlock(sc->lock); return ENXIO; } if (mixer_reinit(dev) != 0) { device_printf(dev, "unable to reinitialize the mixer\n"); + snd_mtxunlock(sc->lock); return ENXIO; } @@ -879,6 +938,8 @@ als_pci_resume(device_t dev) if (sc->rch.dma_was_active) { als_capture_start(&sc->rch); } + + snd_mtxunlock(sc->lock); return 0; } |