* 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;
|
struct resource *reg, *irq;
|
||||||
int regid, irqid;
|
int regid, irqid;
|
||||||
void *ih;
|
void *ih;
|
||||||
|
struct mtx *lock;
|
||||||
|
|
||||||
unsigned int bufsz;
|
unsigned int bufsz;
|
||||||
struct sc_chinfo pch, rch;
|
struct sc_chinfo pch, rch;
|
||||||
@ -90,7 +91,11 @@ static u_int32_t als_format[] = {
|
|||||||
0
|
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 */
|
/* Register Utilities */
|
||||||
@ -199,6 +204,7 @@ alschan_init(kobj_t obj, void *devinfo,
|
|||||||
struct sc_info *sc = devinfo;
|
struct sc_info *sc = devinfo;
|
||||||
struct sc_chinfo *ch;
|
struct sc_chinfo *ch;
|
||||||
|
|
||||||
|
snd_mtxlock(sc->lock);
|
||||||
if (dir == PCMDIR_PLAY) {
|
if (dir == PCMDIR_PLAY) {
|
||||||
ch = &sc->pch;
|
ch = &sc->pch;
|
||||||
ch->gcr_fifo_status = ALS_GCR_FIFO0_STATUS;
|
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->speed = DSP_DEFAULT_SPEED;
|
||||||
ch->buffer = b;
|
ch->buffer = b;
|
||||||
if (sndbuf_alloc(ch->buffer, sc->parent_dmat, sc->bufsz) != 0) {
|
if (sndbuf_alloc(ch->buffer, sc->parent_dmat, sc->bufsz) != 0) {
|
||||||
|
snd_mtxunlock(sc->lock);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
snd_mtxunlock(sc->lock);
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,8 +231,11 @@ static int
|
|||||||
alschan_setformat(kobj_t obj, void *data, u_int32_t format)
|
alschan_setformat(kobj_t obj, void *data, u_int32_t format)
|
||||||
{
|
{
|
||||||
struct sc_chinfo *ch = data;
|
struct sc_chinfo *ch = data;
|
||||||
|
struct sc_info *sc = ch->parent;
|
||||||
|
|
||||||
|
snd_mtxlock(sc->lock);
|
||||||
ch->format = format;
|
ch->format = format;
|
||||||
|
snd_mtxunlock(sc->lock);
|
||||||
return 0;
|
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_chinfo *ch = data, *other;
|
||||||
struct sc_info *sc = ch->parent;
|
struct sc_info *sc = ch->parent;
|
||||||
|
|
||||||
|
snd_mtxlock(sc->lock);
|
||||||
other = (ch->dir == PCMDIR_PLAY) ? &sc->rch : &sc->pch;
|
other = (ch->dir == PCMDIR_PLAY) ? &sc->rch : &sc->pch;
|
||||||
|
|
||||||
/* Deny request if other dma channel is active */
|
/* Deny request if other dma channel is active */
|
||||||
if (other->dma_active) {
|
if (other->dma_active) {
|
||||||
ch->speed = other->speed;
|
ch->speed = other->speed;
|
||||||
|
snd_mtxunlock(sc->lock);
|
||||||
return other->speed;
|
return other->speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
ch->speed = speed;
|
ch->speed = speed;
|
||||||
|
snd_mtxunlock(sc->lock);
|
||||||
return speed;
|
return speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,10 +277,13 @@ static int
|
|||||||
alschan_getptr(kobj_t obj, void *data)
|
alschan_getptr(kobj_t obj, void *data)
|
||||||
{
|
{
|
||||||
struct sc_chinfo *ch = data;
|
struct sc_chinfo *ch = data;
|
||||||
|
struct sc_info *sc = ch->parent;
|
||||||
int32_t pos, sz;
|
int32_t pos, sz;
|
||||||
|
|
||||||
|
snd_mtxlock(sc->lock);
|
||||||
pos = als_gcr_rd(ch->parent, ch->gcr_fifo_status) & 0xffff;
|
pos = als_gcr_rd(ch->parent, ch->gcr_fifo_status) & 0xffff;
|
||||||
sz = sndbuf_getsize(ch->buffer);
|
sz = sndbuf_getsize(ch->buffer);
|
||||||
|
snd_mtxunlock(sc->lock);
|
||||||
return (2 * sz - pos - 1) % sz;
|
return (2 * sz - pos - 1) % sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,7 +395,9 @@ static int
|
|||||||
alspchan_trigger(kobj_t obj, void *data, int go)
|
alspchan_trigger(kobj_t obj, void *data, int go)
|
||||||
{
|
{
|
||||||
struct sc_chinfo *ch = data;
|
struct sc_chinfo *ch = data;
|
||||||
|
struct sc_info *sc = ch->parent;
|
||||||
|
|
||||||
|
snd_mtxlock(sc->lock);
|
||||||
switch(go) {
|
switch(go) {
|
||||||
case PCMTRIG_START:
|
case PCMTRIG_START:
|
||||||
als_playback_start(ch);
|
als_playback_start(ch);
|
||||||
@ -387,6 +406,7 @@ alspchan_trigger(kobj_t obj, void *data, int go)
|
|||||||
als_playback_stop(ch);
|
als_playback_stop(ch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
snd_mtxunlock(sc->lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,7 +488,9 @@ static int
|
|||||||
alsrchan_trigger(kobj_t obj, void *data, int go)
|
alsrchan_trigger(kobj_t obj, void *data, int go)
|
||||||
{
|
{
|
||||||
struct sc_chinfo *ch = data;
|
struct sc_chinfo *ch = data;
|
||||||
|
struct sc_info *sc = ch->parent;
|
||||||
|
|
||||||
|
snd_mtxlock(sc->lock);
|
||||||
switch(go) {
|
switch(go) {
|
||||||
case PCMTRIG_START:
|
case PCMTRIG_START:
|
||||||
als_capture_start(ch);
|
als_capture_start(ch);
|
||||||
@ -477,6 +499,7 @@ alsrchan_trigger(kobj_t obj, void *data, int go)
|
|||||||
als_capture_stop(ch);
|
als_capture_stop(ch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
snd_mtxunlock(sc->lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -574,7 +597,7 @@ static int
|
|||||||
alsmix_setrecsrc(struct snd_mixer *m, u_int32_t src)
|
alsmix_setrecsrc(struct snd_mixer *m, u_int32_t src)
|
||||||
{
|
{
|
||||||
struct sc_info *sc = mix_getdevinfo(m);
|
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++) {
|
for (i = l = r = 0; i < SOUND_MIXER_NRDEVICES; i++) {
|
||||||
if (src & (1 << 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 mixer is really an SB16 mixer */
|
||||||
als_mix_wr(sc, SB16_IMASK_R, r);
|
|
||||||
|
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;
|
return src;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -605,13 +644,20 @@ als_intr(void *p)
|
|||||||
struct sc_info *sc = (struct sc_info *)p;
|
struct sc_info *sc = (struct sc_info *)p;
|
||||||
u_int8_t intr, sb_status;
|
u_int8_t intr, sb_status;
|
||||||
|
|
||||||
|
snd_mtxlock(sc->lock);
|
||||||
intr = als_intr_rd(sc);
|
intr = als_intr_rd(sc);
|
||||||
|
|
||||||
if (intr & 0x80)
|
if (intr & 0x80) {
|
||||||
|
snd_mtxunlock(sc->lock);
|
||||||
chn_intr(sc->pch.channel);
|
chn_intr(sc->pch.channel);
|
||||||
|
snd_mtxlock(sc->lock);
|
||||||
|
}
|
||||||
|
|
||||||
if (intr & 0x40)
|
if (intr & 0x40) {
|
||||||
|
snd_mtxunlock(sc->lock);
|
||||||
chn_intr(sc->rch.channel);
|
chn_intr(sc->rch.channel);
|
||||||
|
snd_mtxlock(sc->lock);
|
||||||
|
}
|
||||||
|
|
||||||
/* ACK interrupt in PCI core */
|
/* ACK interrupt in PCI core */
|
||||||
als_intr_wr(sc, intr);
|
als_intr_wr(sc, intr);
|
||||||
@ -627,6 +673,8 @@ als_intr(void *p)
|
|||||||
als_ack_read(sc, ALS_MIDI_DATA);
|
als_ack_read(sc, ALS_MIDI_DATA);
|
||||||
if (sb_status & ALS_IRQ_CR1E)
|
if (sb_status & ALS_IRQ_CR1E)
|
||||||
als_ack_read(sc, ALS_CR1E_ACK_PORT);
|
als_ack_read(sc, ALS_CR1E_ACK_PORT);
|
||||||
|
|
||||||
|
snd_mtxunlock(sc->lock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -708,6 +756,10 @@ als_resource_free(device_t dev, struct sc_info *sc)
|
|||||||
bus_dma_tag_destroy(sc->parent_dmat);
|
bus_dma_tag_destroy(sc->parent_dmat);
|
||||||
sc->parent_dmat = 0;
|
sc->parent_dmat = 0;
|
||||||
}
|
}
|
||||||
|
if (sc->lock) {
|
||||||
|
snd_mtxfree(sc->lock);
|
||||||
|
sc->lock = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -730,7 +782,7 @@ als_resource_grab(device_t dev, struct sc_info *sc)
|
|||||||
goto bad;
|
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)) {
|
sc, &sc->ih)) {
|
||||||
device_printf(dev, "unable to setup interrupt\n");
|
device_printf(dev, "unable to setup interrupt\n");
|
||||||
goto bad;
|
goto bad;
|
||||||
@ -745,8 +797,8 @@ als_resource_grab(device_t dev, struct sc_info *sc)
|
|||||||
/*filter*/NULL, /*filterarg*/NULL,
|
/*filter*/NULL, /*filterarg*/NULL,
|
||||||
/*maxsize*/sc->bufsz,
|
/*maxsize*/sc->bufsz,
|
||||||
/*nsegments*/1, /*maxsegz*/0x3ffff,
|
/*nsegments*/1, /*maxsegz*/0x3ffff,
|
||||||
/*flags*/0, /*lockfunc*/busdma_lock_mutex,
|
/*flags*/0, /*lockfunc*/NULL,
|
||||||
/*lockarg*/&Giant, &sc->parent_dmat) != 0) {
|
/*lockarg*/NULL, &sc->parent_dmat) != 0) {
|
||||||
device_printf(dev, "unable to create dma tag\n");
|
device_printf(dev, "unable to create dma tag\n");
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
@ -768,6 +820,7 @@ als_pci_attach(device_t dev)
|
|||||||
return ENXIO;
|
return ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sc->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc");
|
||||||
sc->dev = dev;
|
sc->dev = dev;
|
||||||
|
|
||||||
data = pci_read_config(dev, PCIR_COMMAND, 2);
|
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);
|
struct sc_info *sc = pcm_getdevinfo(dev);
|
||||||
|
|
||||||
|
snd_mtxlock(sc->lock);
|
||||||
sc->pch.dma_was_active = als_playback_stop(&sc->pch);
|
sc->pch.dma_was_active = als_playback_stop(&sc->pch);
|
||||||
sc->rch.dma_was_active = als_capture_stop(&sc->rch);
|
sc->rch.dma_was_active = als_capture_stop(&sc->rch);
|
||||||
als_uninit(sc);
|
als_uninit(sc);
|
||||||
|
snd_mtxunlock(sc->lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -862,13 +917,17 @@ als_pci_resume(device_t dev)
|
|||||||
{
|
{
|
||||||
struct sc_info *sc = pcm_getdevinfo(dev);
|
struct sc_info *sc = pcm_getdevinfo(dev);
|
||||||
|
|
||||||
|
snd_mtxlock(sc->lock);
|
||||||
|
|
||||||
if (als_init(sc) != 0) {
|
if (als_init(sc) != 0) {
|
||||||
device_printf(dev, "unable to reinitialize the card\n");
|
device_printf(dev, "unable to reinitialize the card\n");
|
||||||
|
snd_mtxunlock(sc->lock);
|
||||||
return ENXIO;
|
return ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mixer_reinit(dev) != 0) {
|
if (mixer_reinit(dev) != 0) {
|
||||||
device_printf(dev, "unable to reinitialize the mixer\n");
|
device_printf(dev, "unable to reinitialize the mixer\n");
|
||||||
|
snd_mtxunlock(sc->lock);
|
||||||
return ENXIO;
|
return ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -879,6 +938,8 @@ als_pci_resume(device_t dev)
|
|||||||
if (sc->rch.dma_was_active) {
|
if (sc->rch.dma_was_active) {
|
||||||
als_capture_start(&sc->rch);
|
als_capture_start(&sc->rch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
snd_mtxunlock(sc->lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user