summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorJacob Meuser <jakemsr@cvs.openbsd.org>2010-09-21 20:11:45 +0000
committerJacob Meuser <jakemsr@cvs.openbsd.org>2010-09-21 20:11:45 +0000
commit37d466cb419fc3bce08d762cf8bf4cad7f3c5ae5 (patch)
tree947d4ce6fa402c62080624d7fef6e7e809b5c93a /sys/dev
parent15703be3ba349e24ec4e2f26693c4b326667f456 (diff)
much better suspend/resume support
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/eso.c176
-rw-r--r--sys/dev/pci/esovar.h3
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;