summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2010-08-08 17:21:08 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2010-08-08 17:21:08 +0000
commitaaa746a215e8737262be3bc9291170911ed5fa68 (patch)
treee5583e2b6d2cdaffc5282af4024279b18ea5cf18
parentfbb1d5ba236b30f2accaa83aa69118a5ec56fe6b (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.c30
-rw-r--r--sys/dev/ic/vgavar.h25
-rw-r--r--sys/dev/pci/vga_pci.c177
-rw-r--r--sys/dev/pci/vga_pcivar.h17
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_ */