diff options
author | Jacob Meuser <jakemsr@cvs.openbsd.org> | 2010-09-21 20:11:45 +0000 |
---|---|---|
committer | Jacob Meuser <jakemsr@cvs.openbsd.org> | 2010-09-21 20:11:45 +0000 |
commit | 37d466cb419fc3bce08d762cf8bf4cad7f3c5ae5 (patch) | |
tree | 947d4ce6fa402c62080624d7fef6e7e809b5c93a /sys/dev | |
parent | 15703be3ba349e24ec4e2f26693c4b326667f456 (diff) |
much better suspend/resume support
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/eso.c | 176 | ||||
-rw-r--r-- | sys/dev/pci/esovar.h | 3 |
2 files changed, 116 insertions, 63 deletions
diff --git a/sys/dev/pci/eso.c b/sys/dev/pci/eso.c index d28987f954f..82aaca6f19b 100644 --- a/sys/dev/pci/eso.c +++ b/sys/dev/pci/eso.c @@ -1,4 +1,4 @@ -/* $OpenBSD: eso.c,v 1.34 2010/09/07 16:21:44 deraadt Exp $ */ +/* $OpenBSD: eso.c,v 1.35 2010/09/21 20:11:44 jakemsr Exp $ */ /* $NetBSD: eso.c,v 1.48 2006/12/18 23:13:39 kleink Exp $ */ /* @@ -128,7 +128,7 @@ int eso_trigger_output(void *, void *, void *, int, void (*)(void *), void *, struct audio_params *); int eso_trigger_input(void *, void *, void *, int, void (*)(void *), void *, struct audio_params *); -void eso_setup(struct eso_softc *, int); +void eso_setup(struct eso_softc *, int, int); struct audio_hw_if eso_hw_if = { eso_open, @@ -251,7 +251,7 @@ eso_attach(struct device *parent, struct device *self, void *aux) sc->sc_pa = *pa; - eso_setup(sc, 1); + eso_setup(sc, 1, 0); /* map and establish the interrupt. */ if (pci_intr_map(pa, &ih)) { @@ -291,6 +291,7 @@ eso_attach(struct device *parent, struct device *self, void *aux) pci_conf_write(pa->pa_pc, pa->pa_tag, ESO_PCI_DDMAC, vcbase | ESO_PCI_DDMAC_DE); sc->sc_dmac_configured = 1; + sc->sc_dmac_addr = vcbase; printf("%s: mapping Audio 1 DMA using VC I/O space at 0x%lx\n", sc->sc_dev.dv_xname, (unsigned long)vcbase); @@ -320,10 +321,10 @@ eso_attach(struct device *parent, struct device *self, void *aux) } void -eso_setup(struct eso_softc *sc, int verbose) +eso_setup(struct eso_softc *sc, int verbose, int resuming) { struct pci_attach_args *pa = &sc->sc_pa; - uint8_t a2mode, mvctl; + uint8_t a2mode, tmp; int idx; /* Reset the device; bail out upon failure. */ @@ -348,45 +349,90 @@ eso_setup(struct eso_softc *sc, int verbose) eso_write_mixreg(sc, ESO_MIXREG_A2MODE, a2mode); /* Slave Master Volume to Hardware Volume Control Counter, unmask IRQ. */ - mvctl = eso_read_mixreg(sc, ESO_MIXREG_MVCTL); - mvctl &= ~ESO_MIXREG_MVCTL_SPLIT; - mvctl |= ESO_MIXREG_MVCTL_HVIRQM; - eso_write_mixreg(sc, ESO_MIXREG_MVCTL, mvctl); - - /* Set mixer regs to something reasonable, needs work. */ - sc->sc_recmon = sc->sc_spatializer = sc->sc_mvmute = 0; - eso_set_monooutsrc(sc, ESO_MIXREG_MPM_MOMUTE); - eso_set_monoinbypass(sc, 0); - eso_set_preamp(sc, 1); - for (idx = 0; idx < ESO_NGAINDEVS; idx++) { - int v; + tmp = eso_read_mixreg(sc, ESO_MIXREG_MVCTL); + tmp &= ~ESO_MIXREG_MVCTL_SPLIT; + tmp |= ESO_MIXREG_MVCTL_HVIRQM; + eso_write_mixreg(sc, ESO_MIXREG_MVCTL, tmp); + + if (!resuming) { + /* Set mixer regs to something reasonable, needs work. */ + sc->sc_recmon = sc->sc_spatializer = sc->sc_mvmute = 0; + eso_set_monooutsrc(sc, ESO_MIXREG_MPM_MOMUTE); + eso_set_monoinbypass(sc, 0); + eso_set_preamp(sc, 1); + for (idx = 0; idx < ESO_NGAINDEVS; idx++) { + int v; - switch (idx) { - case ESO_MIC_PLAY_VOL: - case ESO_LINE_PLAY_VOL: - case ESO_CD_PLAY_VOL: - case ESO_MONO_PLAY_VOL: - case ESO_AUXB_PLAY_VOL: - case ESO_DAC_REC_VOL: - case ESO_LINE_REC_VOL: - case ESO_SYNTH_REC_VOL: - case ESO_CD_REC_VOL: - case ESO_MONO_REC_VOL: - case ESO_AUXB_REC_VOL: - case ESO_SPATIALIZER: - v = 0; - break; - case ESO_MASTER_VOL: - v = ESO_GAIN_TO_6BIT(AUDIO_MAX_GAIN / 2); - break; - default: - v = ESO_GAIN_TO_4BIT(AUDIO_MAX_GAIN / 2); - break; + switch (idx) { + case ESO_MIC_PLAY_VOL: + case ESO_LINE_PLAY_VOL: + case ESO_CD_PLAY_VOL: + case ESO_MONO_PLAY_VOL: + case ESO_AUXB_PLAY_VOL: + case ESO_DAC_REC_VOL: + case ESO_LINE_REC_VOL: + case ESO_SYNTH_REC_VOL: + case ESO_CD_REC_VOL: + case ESO_MONO_REC_VOL: + case ESO_AUXB_REC_VOL: + case ESO_SPATIALIZER: + v = 0; + break; + case ESO_MASTER_VOL: + v = ESO_GAIN_TO_6BIT(AUDIO_MAX_GAIN / 2); + break; + default: + v = ESO_GAIN_TO_4BIT(AUDIO_MAX_GAIN / 2); + break; + } + sc->sc_gain[idx][ESO_LEFT] = + sc->sc_gain[idx][ESO_RIGHT] = v; + eso_set_gain(sc, idx); } - sc->sc_gain[idx][ESO_LEFT] = sc->sc_gain[idx][ESO_RIGHT] = v; - eso_set_gain(sc, idx); + eso_set_recsrc(sc, ESO_MIXREG_ERS_MIC); + } else { + eso_set_monooutsrc(sc, sc->sc_monooutsrc); + eso_set_monoinbypass(sc, sc->sc_monoinbypass); + eso_set_preamp(sc, sc->sc_preamp); + eso_set_recsrc(sc, sc->sc_recsrc); + + /* recmon */ + tmp = eso_read_ctlreg(sc, ESO_CTLREG_ACTL); + if (sc->sc_recmon) + tmp |= ESO_CTLREG_ACTL_RECMON; + else + tmp &= ~ESO_CTLREG_ACTL_RECMON; + eso_write_ctlreg(sc, ESO_CTLREG_ACTL, tmp); + + /* spatializer enable */ + tmp = eso_read_mixreg(sc, ESO_MIXREG_SPAT); + if (sc->sc_spatializer) + tmp |= ESO_MIXREG_SPAT_ENB; + else + tmp &= ~ESO_MIXREG_SPAT_ENB; + eso_write_mixreg(sc, ESO_MIXREG_SPAT, + tmp | ESO_MIXREG_SPAT_RSTREL); + + /* master volume mute */ + if (sc->sc_mvmute) { + eso_write_mixreg(sc, ESO_MIXREG_LMVM, + eso_read_mixreg(sc, ESO_MIXREG_LMVM) | + ESO_MIXREG_LMVM_MUTE); + eso_write_mixreg(sc, ESO_MIXREG_RMVM, + eso_read_mixreg(sc, ESO_MIXREG_RMVM) | + ESO_MIXREG_RMVM_MUTE); + } else { + eso_write_mixreg(sc, ESO_MIXREG_LMVM, + eso_read_mixreg(sc, ESO_MIXREG_LMVM) & + ~ESO_MIXREG_LMVM_MUTE); + eso_write_mixreg(sc, ESO_MIXREG_RMVM, + eso_read_mixreg(sc, ESO_MIXREG_RMVM) & + ~ESO_MIXREG_RMVM_MUTE); + } + + for (idx = 0; idx < ESO_NGAINDEVS; idx++) + eso_set_gain(sc, idx); } - eso_set_recsrc(sc, ESO_MIXREG_ERS_MIC); } void @@ -415,6 +461,7 @@ eso_defer(struct device *self) addr | ESO_PCI_DDMAC_DE); sc->sc_dmac_iot = sc->sc_iot; sc->sc_dmac_configured = 1; + sc->sc_dmac_addr = addr; printf("mapping Audio 1 DMA using I/O space at 0x%lx\n", (unsigned long)addr); @@ -821,7 +868,7 @@ eso_halt_output(void *hdl) ESO_IO_A2DMAM_DMAENB); sc->sc_pintr = NULL; - error = tsleep(&sc->sc_pintr, PCATCH | PWAIT, "esoho", sc->sc_pdrain); + error = tsleep(&sc->sc_pintr, PWAIT, "esoho", sc->sc_pdrain); splx(s); /* Shut down DMA completely. */ @@ -848,7 +895,7 @@ eso_halt_input(void *hdl) DMA37MD_WRITE | DMA37MD_DEMAND); sc->sc_rintr = NULL; - error = tsleep(&sc->sc_rintr, PCATCH | PWAIT, "esohi", sc->sc_rdrain); + error = tsleep(&sc->sc_rintr, PWAIT, "esohi", sc->sc_rdrain); splx(s); /* Shut down DMA completely. */ @@ -1689,9 +1736,8 @@ eso_trigger_output(void *hdl, void *start, void *end, int blksize, sc->sc_parg = arg; /* Compute drain timeout. */ - sc->sc_pdrain = (blksize * NBBY * hz) / - (param->sample_rate * param->channels * - param->precision * param->factor) + 2; /* slop */ + sc->sc_pdrain = hz * (blksize * 3 / 2) / + (param->sample_rate * param->channels * param->bps * param->factor); /* DMA transfer count (in `words'!) reload using 2's complement. */ blksize = -(blksize >> 1); @@ -1772,9 +1818,8 @@ eso_trigger_input(void *hdl, void *start, void *end, int blksize, sc->sc_rarg = arg; /* Compute drain timeout. */ - sc->sc_rdrain = (blksize * NBBY * hz) / - (param->sample_rate * param->channels * - param->precision * param->factor) + 2; /* slop */ + sc->sc_rdrain = hz * (blksize * 3 / 2) / + (param->sample_rate * param->channels * param->bps * param->factor); /* Set up ADC DMA converter parameters. */ actl = eso_read_ctlreg(sc, ESO_CTLREG_ACTL); @@ -2057,26 +2102,33 @@ eso_set_gain(struct eso_softc *sc, uint port) int eso_activate(struct device *self, int act) { - struct eso_softc *sc = (struct eso_softc *)self; + struct eso_softc *sc = (struct eso_softc *)self; + uint8_t tmp; + int rv = 0; switch (act) { + case DVACT_QUIESCE: + rv = config_activate_children(self, act); + tmp = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ESO_IO_IRQCTL); + tmp &= ~(ESO_IO_IRQCTL_MASK); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, ESO_IO_IRQCTL, tmp); + break; case DVACT_SUSPEND: - eso_halt_output(sc); - eso_halt_input(sc); - bus_space_write_1(sc->sc_iot, sc->sc_ioh, ESO_IO_A2DMAM, 0); - bus_space_write_1(sc->sc_dmac_iot, - sc->sc_dmac_ioh, ESO_DMAC_CLEAR, 0); - bus_space_write_1(sc->sc_sb_iot, - sc->sc_sb_ioh, ESO_SB_STATUSFLAGS, 3); - + bus_space_write_1(sc->sc_dmac_iot, sc->sc_dmac_ioh, + ESO_DMAC_CLEAR, 0); + bus_space_write_1(sc->sc_sb_iot, sc->sc_sb_ioh, + ESO_SB_STATUSFLAGS, 3); /* shut down dma */ - pci_conf_write(sc->sc_pa.pa_pc, - sc->sc_pa.pa_tag, ESO_PCI_DDMAC, 0); + pci_conf_write(sc->sc_pa.pa_pc, sc->sc_pa.pa_tag, + ESO_PCI_DDMAC, 0); break; case DVACT_RESUME: - eso_setup(sc, 0); + eso_setup(sc, 1, 1); + pci_conf_write(sc->sc_pa.pa_pc, sc->sc_pa.pa_tag, + ESO_PCI_DDMAC, sc->sc_dmac_addr | ESO_PCI_DDMAC_DE); + rv = config_activate_children(self, act); break; } - return 0; + return (rv); } diff --git a/sys/dev/pci/esovar.h b/sys/dev/pci/esovar.h index 2dd129c9ffe..677a495b282 100644 --- a/sys/dev/pci/esovar.h +++ b/sys/dev/pci/esovar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: esovar.h,v 1.5 2010/09/07 16:21:44 deraadt Exp $ */ +/* $OpenBSD: esovar.h,v 1.6 2010/09/21 20:11:44 jakemsr Exp $ */ /* $NetBSD: esovar.h,v 1.5 2004/05/25 21:38:11 kleink Exp $ */ /* @@ -108,6 +108,7 @@ struct eso_softc { /* Audio 1 DMAC device */ unsigned int sc_dmac_configured; + bus_addr_t sc_dmac_addr; bus_space_tag_t sc_dmac_iot; bus_space_handle_t sc_dmac_ioh; |