* 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:
parent
7233abab86
commit
1adf8286e7
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user