* 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>
This commit is contained in:
Alexander Leidinger 2005-07-31 11:01:13 +00:00
parent 7233abab86
commit 1adf8286e7

View File

@ -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;
}