summaryrefslogtreecommitdiff
path: root/sys
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 /sys
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@
Diffstat (limited to 'sys')
-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_ */