summaryrefslogtreecommitdiffstats
path: root/sys/dev/sound
diff options
context:
space:
mode:
authornetchild <netchild@FreeBSD.org>2005-07-31 11:01:13 +0000
committernetchild <netchild@FreeBSD.org>2005-07-31 11:01:13 +0000
commit24f05a42fb8ffb125b0a887f8cda4aec81af4611 (patch)
tree04e4a4598cfd56940d9f573f52731eec5bdfcbba /sys/dev/sound
parentb3a4958eb7b757b4d5be9b22d1a916f2a37b24ee (diff)
downloadFreeBSD-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.c79
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;
}
OpenPOWER on IntegriCloud