diff options
author | joshua stein <jcs@cvs.openbsd.org> | 2001-12-20 04:50:07 +0000 |
---|---|---|
committer | joshua stein <jcs@cvs.openbsd.org> | 2001-12-20 04:50:07 +0000 |
commit | 99f6bbd894a8f39be6e3ac6ef157f316e9887ebe (patch) | |
tree | 652cd6bab5d218bd3c77100b08240b7add321d1e | |
parent | 02a668ef017de4084d912eaa54c98e1599c9f6a5 (diff) |
add powerhook support to handle APM resumes correctly, fixes PR 1814
ok provos@ and markus@
-rw-r--r-- | sys/dev/pci/yds.c | 225 | ||||
-rw-r--r-- | sys/dev/pci/ydsvar.h | 10 |
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_ */ |