summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjoshua stein <jcs@cvs.openbsd.org>2001-12-20 04:50:07 +0000
committerjoshua stein <jcs@cvs.openbsd.org>2001-12-20 04:50:07 +0000
commit99f6bbd894a8f39be6e3ac6ef157f316e9887ebe (patch)
tree652cd6bab5d218bd3c77100b08240b7add321d1e
parent02a668ef017de4084d912eaa54c98e1599c9f6a5 (diff)
add powerhook support to handle APM resumes correctly, fixes PR 1814
ok provos@ and markus@
-rw-r--r--sys/dev/pci/yds.c225
-rw-r--r--sys/dev/pci/ydsvar.h10
2 files changed, 149 insertions, 86 deletions
diff --git a/sys/dev/pci/yds.c b/sys/dev/pci/yds.c
index 52f7dd33cae..e41548c4101 100644
--- a/sys/dev/pci/yds.c
+++ b/sys/dev/pci/yds.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: yds.c,v 1.9 2001/12/07 17:08:35 deraadt Exp $ */
+/* $OpenBSD: yds.c,v 1.10 2001/12/20 04:50:06 jcs Exp $ */
/* $NetBSD: yds.c,v 1.5 2001/05/21 23:55:04 minoura Exp $ */
/*
@@ -197,6 +197,9 @@ static u_int32_t yds_get_lpfq __P((u_int));
static u_int32_t yds_get_lpfk __P((u_int));
static struct yds_dma *yds_find_dma __P((struct yds_softc *, void *));
+void yds_powerhook __P((int, void *));
+int yds_init __P((void *sc));
+
#ifdef AUDIO_DEBUG
static void yds_dump_play_slot __P((struct yds_softc *, int));
#define YDS_DUMP_PLAY_SLOT(n,sc,bank) \
@@ -663,9 +666,8 @@ yds_attach(parent, self, aux)
struct yds_codec_softc *codec;
char devinfo[256];
mixer_ctrl_t ctl;
- int i, r, to;
+ int i, r;
int revision;
- int ac97_id2;
pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo);
revision = PCI_REVISION(pa->pa_class);
@@ -716,6 +718,7 @@ yds_attach(parent, self, aux)
reg = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
reg |= (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE |
PCI_COMMAND_MASTER_ENABLE);
+
pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, reg);
reg = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
@@ -723,88 +726,8 @@ yds_attach(parent, self, aux)
for (i = 0x80; i < 0xc0; i += 2)
YWRITE2(sc, i, 0);
- /* Download microcode */
- if (yds_download_mcode(sc)) {
- printf("%s: download microcode failed\n", sc->sc_dev.dv_xname);
- return;
- }
- /* Allocate DMA buffers */
- if (yds_allocate_slots(sc)) {
- printf("%s: could not allocate slots\n", sc->sc_dev.dv_xname);
- return;
- }
-
- /* Warm reset */
- reg = pci_conf_read(pc, pa->pa_tag, YDS_PCI_DSCTRL);
- pci_conf_write(pc, pa->pa_tag, YDS_PCI_DSCTRL, reg | YDS_DSCTRL_WRST);
- delay(50000);
-
- /*
- * Detect primary/secondary AC97
- * YMF754 Hardware Specification Rev 1.01 page 24
- */
- reg = pci_conf_read(pc, pa->pa_tag, YDS_PCI_DSCTRL);
- pci_conf_write(pc, pa->pa_tag, YDS_PCI_DSCTRL,
- reg & ~YDS_DSCTRL_CRST);
- delay(400000); /* Needed for 740C. */
-
- /* Primary */
- for (to = 0; to < AC97_TIMEOUT; to++) {
- if ((YREAD2(sc, AC97_STAT_ADDR1) & AC97_BUSY) == 0)
- break;
- delay(1);
- }
- if (to == AC97_TIMEOUT) {
- printf("%s: no AC97 avaliable\n", sc->sc_dev.dv_xname);
- return;
- }
-
- /* Secondary */
- /* Secondary AC97 is used for 4ch audio. Currently unused. */
- ac97_id2 = -1;
- if ((YREAD2(sc, YDS_ACTIVITY) & YDS_ACTIVITY_DOCKA) == 0)
- goto detected;
-#if 0 /* reset secondary... */
- YWRITE2(sc, YDS_GPIO_OCTRL,
- YREAD2(sc, YDS_GPIO_OCTRL) & ~YDS_GPIO_GPO2);
- YWRITE2(sc, YDS_GPIO_FUNCE,
- (YREAD2(sc, YDS_GPIO_FUNCE)&(~YDS_GPIO_GPC2))|YDS_GPIO_GPE2);
-#endif
- for (to = 0; to < AC97_TIMEOUT; to++) {
- if ((YREAD2(sc, AC97_STAT_ADDR2) & AC97_BUSY) == 0)
- break;
- delay(1);
- }
- if (to < AC97_TIMEOUT) {
- /* detect id */
- for (ac97_id2 = 1; ac97_id2 < 4; ac97_id2++) {
- YWRITE2(sc, AC97_CMD_ADDR,
- AC97_CMD_READ | AC97_ID(ac97_id2) | 0x28);
-
- for (to = 0; to < AC97_TIMEOUT; to++) {
- if ((YREAD2(sc, AC97_STAT_ADDR2) & AC97_BUSY)
- == 0)
- goto detected;
- delay(1);
- }
- }
- if (ac97_id2 == 4)
- ac97_id2 = -1;
-detected:
- ;
- }
-
- pci_conf_write(pc, pa->pa_tag, YDS_PCI_DSCTRL,
- reg | YDS_DSCTRL_CRST);
- delay (20);
- pci_conf_write(pc, pa->pa_tag, YDS_PCI_DSCTRL,
- reg & ~YDS_DSCTRL_CRST);
- delay (400000);
- for (to = 0; to < AC97_TIMEOUT; to++) {
- if ((YREAD2(sc, AC97_STAT_ADDR1) & AC97_BUSY) == 0)
- break;
- delay(1);
- }
+ /* Initialize the device */
+ yds_init(sc);
/*
* Attach ac97 codec
@@ -876,6 +799,10 @@ detected:
sc->sc_legacy_iot = pa->pa_iot;
config_defer((struct device*) sc, yds_configure_legacy);
+
+ /* Watch for power changes */
+ sc->suspend = PWR_RESUME;
+ sc->powerhook = powerhook_establish(yds_powerhook, sc);
}
int
@@ -1838,3 +1765,131 @@ yds_get_props(addr)
return (AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT |
AUDIO_PROP_FULLDUPLEX);
}
+
+void
+yds_powerhook(why, self)
+ int why;
+ void *self;
+{
+ struct yds_softc *sc = (struct yds_softc *)self;
+
+ if (why != PWR_RESUME) {
+ /* Power down */
+ DPRINTF(("yds: power down\n"));
+ sc->suspend = why;
+
+ } else {
+ /* Wake up */
+ DPRINTF(("yds: power resume\n"));
+ if (sc->suspend == PWR_RESUME) {
+ printf("%s: resume without suspend?\n",
+ sc->sc_dev.dv_xname);
+ sc->suspend = why;
+ return;
+ }
+ sc->suspend = why;
+ yds_init(sc);
+ (sc->sc_codec[0].codec_if->vtbl->restore_ports)(sc->sc_codec[0].codec_if);
+ }
+}
+
+int
+yds_init(sc_)
+ void *sc_;
+{
+ struct yds_softc *sc = sc_;
+ u_int32_t reg;
+
+ pci_chipset_tag_t pc = sc->sc_pc;
+
+ int to;
+
+ DPRINTF(("in yds_init()\n"));
+
+ /* Download microcode */
+ if (yds_download_mcode(sc)) {
+ printf("%s: download microcode failed\n", sc->sc_dev.dv_xname);
+ return -1;
+ }
+ /* Allocate DMA buffers */
+ if (yds_allocate_slots(sc)) {
+ printf("%s: could not allocate slots\n", sc->sc_dev.dv_xname);
+ return -1;
+ }
+
+ /* Warm reset */
+ reg = pci_conf_read(pc, sc->sc_pcitag, YDS_PCI_DSCTRL);
+ pci_conf_write(pc, sc->sc_pcitag, YDS_PCI_DSCTRL, reg | YDS_DSCTRL_WRST);
+ delay(50000);
+
+ /*
+ * Detect primary/secondary AC97
+ * YMF754 Hardware Specification Rev 1.01 page 24
+ */
+ reg = pci_conf_read(pc, sc->sc_pcitag, YDS_PCI_DSCTRL);
+ pci_conf_write(pc, sc->sc_pcitag, YDS_PCI_DSCTRL,
+ reg & ~YDS_DSCTRL_CRST);
+ delay(400000); /* Needed for 740C. */
+
+ /* Primary */
+ for (to = 0; to < AC97_TIMEOUT; to++) {
+ if ((YREAD2(sc, AC97_STAT_ADDR1) & AC97_BUSY) == 0)
+ break;
+ delay(1);
+ }
+ if (to == AC97_TIMEOUT) {
+ printf("%s: no AC97 avaliable\n", sc->sc_dev.dv_xname);
+ return -1;
+ }
+
+ /* Secondary */
+ /* Secondary AC97 is used for 4ch audio. Currently unused. */
+ ac97_id2 = -1;
+ if ((YREAD2(sc, YDS_ACTIVITY) & YDS_ACTIVITY_DOCKA) == 0)
+ goto detected;
+#if 0 /* reset secondary... */
+ YWRITE2(sc, YDS_GPIO_OCTRL,
+ YREAD2(sc, YDS_GPIO_OCTRL) & ~YDS_GPIO_GPO2);
+ YWRITE2(sc, YDS_GPIO_FUNCE,
+ (YREAD2(sc, YDS_GPIO_FUNCE)&(~YDS_GPIO_GPC2))|YDS_GPIO_GPE2);
+#endif
+ for (to = 0; to < AC97_TIMEOUT; to++) {
+ if ((YREAD2(sc, AC97_STAT_ADDR2) & AC97_BUSY) == 0)
+ break;
+ delay(1);
+ }
+ if (to < AC97_TIMEOUT) {
+ /* detect id */
+ for (ac97_id2 = 1; ac97_id2 < 4; ac97_id2++) {
+ YWRITE2(sc, AC97_CMD_ADDR,
+ AC97_CMD_READ | AC97_ID(ac97_id2) | 0x28);
+
+ for (to = 0; to < AC97_TIMEOUT; to++) {
+ if ((YREAD2(sc, AC97_STAT_ADDR2) & AC97_BUSY)
+ == 0)
+ goto detected;
+ delay(1);
+ }
+ }
+ if (ac97_id2 == 4)
+ ac97_id2 = -1;
+detected:
+ ;
+ }
+
+ pci_conf_write(pc, sc->sc_pcitag, YDS_PCI_DSCTRL,
+ reg | YDS_DSCTRL_CRST);
+ delay (20);
+ pci_conf_write(pc, sc->sc_pcitag, YDS_PCI_DSCTRL,
+ reg & ~YDS_DSCTRL_CRST);
+ delay (400000);
+ for (to = 0; to < AC97_TIMEOUT; to++) {
+ if ((YREAD2(sc, AC97_STAT_ADDR1) & AC97_BUSY) == 0)
+ break;
+ delay(1);
+ }
+
+ DPRINTF(("out of yds_init()\n"));
+
+ return ac97_id2;
+}
diff --git a/sys/dev/pci/ydsvar.h b/sys/dev/pci/ydsvar.h
index 5b4036d7b55..d75cb6939ba 100644
--- a/sys/dev/pci/ydsvar.h
+++ b/sys/dev/pci/ydsvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ydsvar.h,v 1.2 2001/07/08 06:43:27 fgsch Exp $ */
+/* $OpenBSD: ydsvar.h,v 1.3 2001/12/20 04:50:06 jcs Exp $ */
/* $NetBSD$ */
/*
@@ -109,8 +109,16 @@ struct yds_softc {
bus_space_handle_t sc_opl_ioh;
struct device *sc_mpu;
bus_space_handle_t sc_mpu_ioh;
+
+ /*
+ * Suspend/resume support
+ */
+ void *powerhook;
+ int suspend;
};
#define sc_opl_iot sc_legacy_iot
#define sc_mpu_iot sc_legacy_iot
+int ac97_id2;
+
#endif /* _DEV_PCI_YDSVAR_H_ */