diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2010-08-08 17:21:08 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2010-08-08 17:21:08 +0000 |
commit | aaa746a215e8737262be3bc9291170911ed5fa68 (patch) | |
tree | e5583e2b6d2cdaffc5282af4024279b18ea5cf18 | |
parent | fbb1d5ba236b30f2accaa83aa69118a5ec56fe6b (diff) |
Try to save the vga hardware state around suspend, and also redisplay the
textmode video memory contents if we had to POST the vga bios.
ok deraadt@ kettenis@
-rw-r--r-- | sys/dev/ic/vga.c | 30 | ||||
-rw-r--r-- | sys/dev/ic/vgavar.h | 25 | ||||
-rw-r--r-- | sys/dev/pci/vga_pci.c | 177 | ||||
-rw-r--r-- | sys/dev/pci/vga_pcivar.h | 17 |
4 files changed, 205 insertions, 44 deletions
diff --git a/sys/dev/ic/vga.c b/sys/dev/ic/vga.c index f351b216f9b..af6374c1cf1 100644 --- a/sys/dev/ic/vga.c +++ b/sys/dev/ic/vga.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vga.c,v 1.52 2009/09/05 14:09:35 miod Exp $ */ +/* $OpenBSD: vga.c,v 1.53 2010/08/08 17:21:05 miod Exp $ */ /* $NetBSD: vga.c,v 1.28.2.1 2000/06/30 16:27:47 simonb Exp $ */ /*- @@ -96,21 +96,6 @@ static struct vgafont { 0 }; -struct vgascreen { - struct pcdisplayscreen pcs; - - LIST_ENTRY(vgascreen) next; - - struct vga_config *cfg; - - /* videostate */ - struct vgafont *fontset1, *fontset2; - /* font data */ - - int mindispoffset, maxdispoffset; - int vga_rollover; -}; - int vgaconsole, vga_console_type, vga_console_attached; struct vgascreen vga_console_screen; struct vga_config vga_console_vc; @@ -522,9 +507,6 @@ vga_init(vc, iot, memt) LIST_INIT(&vc->screens); vc->active = NULL; vc->currenttype = vh->vh_mono ? &vga_stdscreen_mono : &vga_stdscreen; -#if 0 - callout_init(&vc->vc_switch_callout); -#endif vc->vc_fonts[0] = &vga_builtinfont; for (i = 1; i < 8; i++) @@ -535,16 +517,16 @@ vga_init(vc, iot, memt) vga_save_palette(vc); } -void +struct vga_config * vga_common_attach(self, iot, memt, type) struct device *self; bus_space_tag_t iot, memt; int type; { - vga_extended_attach(self, iot, memt, type, NULL); + return vga_extended_attach(self, iot, memt, type, NULL); } -void +struct vga_config * vga_extended_attach(self, iot, memt, type, map) struct device *self; bus_space_tag_t iot, memt; @@ -563,7 +545,7 @@ vga_extended_attach(self, iot, memt, type, map) } else { vc = malloc(sizeof(*vc), M_DEVBUF, M_NOWAIT | M_ZERO); if (vc == NULL) - return; + return NULL; vga_init(vc, iot, memt); } @@ -578,6 +560,8 @@ vga_extended_attach(self, iot, memt, type, map) aa.defaultscreens = 0; config_found_sm(self, &aa, wsemuldisplaydevprint, displaysubmatch); + + return vc; } int diff --git a/sys/dev/ic/vgavar.h b/sys/dev/ic/vgavar.h index c018b7bcf03..fd36b95ba49 100644 --- a/sys/dev/ic/vgavar.h +++ b/sys/dev/ic/vgavar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vgavar.h,v 1.9 2009/02/01 14:37:22 miod Exp $ */ +/* $OpenBSD: vgavar.h,v 1.10 2010/08/08 17:21:05 miod Exp $ */ /* $NetBSD: vgavar.h,v 1.4 2000/06/17 07:11:50 soda Exp $ */ /* @@ -40,6 +40,19 @@ struct vga_handle { #define vh_ioh_6845 vh_ph.ph_ioh_6845 #define vh_memh vh_ph.ph_memh +struct vgascreen { + struct pcdisplayscreen pcs; + LIST_ENTRY(vgascreen) next; + + /* videostate */ + struct vga_config *cfg; + /* font data */ + struct vgafont *fontset1, *fontset2; + + int mindispoffset, maxdispoffset; + int vga_rollover; +}; + struct vga_config { struct vga_handle hdl; @@ -168,10 +181,12 @@ static inline void _vga_gdc_write(vh, reg, val) pcdisplay_6845_write(&(vh)->vh_ph, reg, val) int vga_common_probe(bus_space_tag_t, bus_space_tag_t); -void vga_common_attach(struct device *, bus_space_tag_t, - bus_space_tag_t, int); -void vga_extended_attach(struct device *, bus_space_tag_t, - bus_space_tag_t, int, paddr_t (*)(void *, off_t, int)); +struct vga_config * + vga_common_attach(struct device *, bus_space_tag_t, bus_space_tag_t, + int); +struct vga_config * + vga_extended_attach(struct device *, bus_space_tag_t, bus_space_tag_t, + int, paddr_t (*)(void *, off_t, int)); int vga_is_console(bus_space_tag_t, int); int vga_cnattach(bus_space_tag_t, bus_space_tag_t, int, int); diff --git a/sys/dev/pci/vga_pci.c b/sys/dev/pci/vga_pci.c index 358f8260d69..fba8b4de3f4 100644 --- a/sys/dev/pci/vga_pci.c +++ b/sys/dev/pci/vga_pci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vga_pci.c,v 1.61 2010/08/06 18:32:38 marco Exp $ */ +/* $OpenBSD: vga_pci.c,v 1.62 2010/08/08 17:21:07 miod Exp $ */ /* $NetBSD: vga_pci.c,v 1.3 1998/06/08 06:55:58 thorpej Exp $ */ /* @@ -63,6 +63,9 @@ */ #include "vga.h" +#if defined(__i386__) || defined(__amd64__) +#include "acpi.h" +#endif #include <sys/param.h> #include <sys/systm.h> @@ -101,9 +104,6 @@ #include "intagp.h" #include "drm.h" -#if defined(__i386__) || defined(__amd64__) -#include "acpi.h" -#endif int vga_pci_match(struct device *, void *, void *); void vga_pci_attach(struct device *, struct device *, void *); @@ -121,8 +121,13 @@ int vga_drm_print(void *, const char *); #endif #ifdef VESAFB -int vesafb_putcmap(struct vga_pci_softc *, struct wsdisplay_cmap *); -int vesafb_getcmap(struct vga_pci_softc *, struct wsdisplay_cmap *); +int vesafb_putcmap(struct vga_pci_softc *, struct wsdisplay_cmap *); +int vesafb_getcmap(struct vga_pci_softc *, struct wsdisplay_cmap *); +#endif + +#if !defined(SMALL_KERNEL) && NACPI > 0 +void vga_save_state(struct vga_pci_softc *); +void vga_restore_state(struct vga_pci_softc *); #endif @@ -243,24 +248,25 @@ vga_pci_attach(struct device *parent, struct device *self, void *aux) if (vesabios_softc != NULL && vesabios_softc->sc_nmodes > 0) { sc->sc_textmode = vesafb_get_mode(sc); printf(", vesafb\n"); - vga_extended_attach(self, pa->pa_iot, pa->pa_memt, + sc->sc_vc = vga_extended_attach(self, pa->pa_iot, pa->pa_memt, WSDISPLAY_TYPE_PCIVGA, vga_pci_mmap); return; } #endif printf("\n"); - vga_common_attach(self, pa->pa_iot, pa->pa_memt, + sc->sc_vc = vga_common_attach(self, pa->pa_iot, pa->pa_memt, WSDISPLAY_TYPE_PCIVGA); vga_pci_bar_init(sc, pa); +#if !defined(SMALL_KERNEL) && NACPI > 0 + #ifdef X86EMU if ((sc->sc_posth = vga_post_init(pa->pa_bus, pa->pa_device, pa->pa_function)) == NULL) printf("couldn't set up vga POST handler\n"); #endif -#if !defined(SMALL_KERNEL) && NACPI > 0 vend = PCI_VENDOR(pa->pa_id); prod = PCI_PRODUCT(pa->pa_id); subid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); @@ -300,22 +306,36 @@ vga_pci_activate(struct device *self, int act) { int rv = 0; -#if defined (X86EMU) && NACPI > 0 +#if !defined(SMALL_KERNEL) && NACPI > 0 struct vga_pci_softc *sc = (struct vga_pci_softc *)self; #endif switch (act) { case DVACT_SUSPEND: rv = config_activate_children(self, act); +#if !defined(SMALL_KERNEL) && NACPI > 0 + /* + * Save the common vga state. This should theoretically only + * be necessary if we intend to POST, but it is preferrable + * to do it unconditionnaly, as many systems do not restore + * this state correctly upon resume. + */ + vga_save_state(sc); +#endif break; case DVACT_RESUME: -#if defined (X86EMU) && NACPI > 0 +#if !defined(SMALL_KERNEL) && NACPI > 0 +#if defined (X86EMU) if (vga_pci_do_post) { +#ifdef obnoxious printf("%s: reposting video using BIOS. Is this neccessary?\n", sc->sc_dev.dv_xname); +#endif vga_post_call(sc->sc_posth); } #endif + vga_restore_state(sc); +#endif rv = config_activate_children(self, act); break; } @@ -593,3 +613,138 @@ vga_pci_bar_unmap(struct vga_pci_bar *bar) bus_space_unmap(bar->bst, bar->bsh, bar->size); } } + +#if !defined(SMALL_KERNEL) && NACPI > 0 +void +vga_save_state(struct vga_pci_softc *sc) +{ + struct vga_config *vc = sc->sc_vc; + struct vga_handle *vh; + struct vgascreen *scr; + size_t i; + char *buf; + + if (vc == NULL) + return; + + vh = &vc->hdl; + + /* + * Save sequencer registers + */ + vga_ts_write(vh, syncreset, 1); /* stop sequencer */ + buf = (char *)&sc->sc_save_ts; + *buf++ = 0; + for (i = 1; i < sizeof(sc->sc_save_ts); i++) + *buf++ = _vga_ts_read(vh, i); + vga_ts_write(vh, syncreset, 3); /* start sequencer */ + /* pretend screen is not blanked */ + sc->sc_save_ts.mode &= ~0x20; + sc->sc_save_ts.mode |= 0x80; + + /* + * Save CRTC registers + */ + buf = (char *)&sc->sc_save_crtc; + for (i = 0; i < sizeof(sc->sc_save_crtc); i++) + *buf++ = _pcdisplay_6845_read(&vh->vh_ph, i); + + /* + * Save ATC registers + */ + buf = (char *)&sc->sc_save_atc; + for (i = 0; i < sizeof(sc->sc_save_atc); i++) + *buf++ = _vga_attr_read(vh, i); + + /* + * Save GDC registers + */ + buf = (char *)&sc->sc_save_gdc; + for (i = 0; i < sizeof(sc->sc_save_gdc); i++) + *buf++ = _vga_gdc_read(vh, i); + + vga_save_palette(vc); + + /* XXX should also save font data */ + + /* + * Save current screen contents if we have backing store for it, + * and intend to POST on resume. + * XXX Since we don't allocate backing store unless the second VT is + * XXX created, we could theoretically have no backing store available + * XXX at this point. + */ + if (vga_pci_do_post) { + scr = vc->active; + if (scr != NULL && scr->pcs.active && scr->pcs.mem != NULL) + bus_space_read_region_2(vh->vh_memt, vh->vh_memh, + scr->pcs.dispoffset, scr->pcs.mem, + scr->pcs.type->ncols * scr->pcs.type->nrows); + } +} + +void +vga_restore_state(struct vga_pci_softc *sc) +{ + struct vga_config *vc = sc->sc_vc; + struct vga_handle *vh; + struct vgascreen *scr; + size_t i; + char *buf; + + if (vc == NULL) + return; + + vh = &vc->hdl; + + /* + * Restore sequencer registers + */ + vga_ts_write(vh, syncreset, 1); /* stop sequencer */ + buf = (char *)&sc->sc_save_ts + 1; + for (i = 1; i < sizeof(sc->sc_save_ts); i++) + _vga_ts_write(vh, i, *buf++); + vga_ts_write(vh, syncreset, 3); /* start sequencer */ + + /* + * Restore CRTC registers + */ + /* unprotect registers 00-07 */ + vga_6845_write(vh, vsynce, + vga_6845_read(vh, vsynce) & ~0x80); + buf = (char *)&sc->sc_save_crtc; + for (i = 0; i < sizeof(sc->sc_save_crtc); i++) + _pcdisplay_6845_write(&vh->vh_ph, i, *buf++); + + /* + * Restore ATC registers + */ + buf = (char *)&sc->sc_save_atc; + for (i = 0; i < sizeof(sc->sc_save_atc); i++) + _vga_attr_write(vh, i, *buf++); + + /* + * Restore GDC registers + */ + buf = (char *)&sc->sc_save_gdc; + for (i = 0; i < sizeof(sc->sc_save_gdc); i++) + _vga_gdc_write(vh, i, *buf++); + + vga_restore_palette(vc); + + /* + * Restore current screen contents if we have backing store for it, + * and have POSTed on resume. + * XXX Since we don't allocate backing store unless the second VT is + * XXX created, we could theoretically have no backing store available + * XXX at this point. + */ + if (vga_pci_do_post) { + scr = vc->active; + if (scr != NULL && scr->pcs.active && scr->pcs.mem != NULL) + bus_space_write_region_2(vh->vh_memt, vh->vh_memh, + scr->pcs.dispoffset, scr->pcs.mem, + scr->pcs.type->ncols * scr->pcs.type->nrows); + } +} +#endif diff --git a/sys/dev/pci/vga_pcivar.h b/sys/dev/pci/vga_pcivar.h index c800258c256..249004a1d93 100644 --- a/sys/dev/pci/vga_pcivar.h +++ b/sys/dev/pci/vga_pcivar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vga_pcivar.h,v 1.13 2009/06/06 04:38:18 pirofti Exp $ */ +/* $OpenBSD: vga_pcivar.h,v 1.14 2010/08/08 17:21:07 miod Exp $ */ /* $NetBSD: vga_pcivar.h,v 1.1 1998/03/22 15:16:19 drochner Exp $ */ /* @@ -54,9 +54,16 @@ struct vga_pci_bar { struct vga_pci_softc { struct device sc_dev; + struct vga_config *sc_vc; struct pci_attach_args pa; struct vga_pci_bar *bars[VGA_PCI_MAX_BARS]; +#if NACPI > 0 + struct reg_vgats sc_save_ts; + struct reg_mc6845 sc_save_crtc; + struct reg_vgaattr sc_save_atc; + struct reg_vgagdc sc_save_gdc; +#endif #ifdef X86EMU struct vga_post *sc_posth; #endif @@ -84,10 +91,10 @@ struct vga_pci_bar *vga_pci_bar_map(struct vga_pci_softc *, int, void vga_pci_bar_unmap(struct vga_pci_bar*); #ifdef VESAFB -int vesafb_find_mode(struct vga_pci_softc *, int, int, int); -void vesafb_set_mode(struct vga_pci_softc *, int); -int vesafb_get_mode(struct vga_pci_softc *); -int vesafb_get_supported_depth(struct vga_pci_softc *); +int vesafb_find_mode(struct vga_pci_softc *, int, int, int); +void vesafb_set_mode(struct vga_pci_softc *, int); +int vesafb_get_mode(struct vga_pci_softc *); +int vesafb_get_supported_depth(struct vga_pci_softc *); #endif #endif /* _PCI_VGA_PCIVAR_H_ */ |