From 528433ba71db7189eaeab212aac3219d902cf443 Mon Sep 17 00:00:00 2001
From: Ian Dowse <iedowse@FreeBSD.org>
Date: Mon, 28 Feb 2005 21:06:14 +0000
Subject: [PATCH] Save and restore the VGA state across a suspend-resume cycle.
 This is particularly useful when VESA is available (either `options VESA' or
 load the vesa module), as BIOSes in some notebooks may correctly save and
 restore LCD panel settings using VESA in cases where calling the video BIOS
 POST is not effective. On some systems it may also be necessary to set the
 hw.acpi.reset_video sysctl to 0.

---
 sys/dev/fb/vgareg.h |  1 +
 sys/isa/vga_isa.c   | 55 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 56 insertions(+)

diff --git a/sys/dev/fb/vgareg.h b/sys/dev/fb/vgareg.h
index e26c214e21c5..4ccef40d616f 100644
--- a/sys/dev/fb/vgareg.h
+++ b/sys/dev/fb/vgareg.h
@@ -69,6 +69,7 @@
 struct video_adapter;
 typedef struct vga_softc {
 	struct video_adapter	*adp;
+	void			*state_buf;
 #ifdef FB_INSTALL_CDEV
 	genfb_softc_t		gensc;
 #endif
diff --git a/sys/isa/vga_isa.c b/sys/isa/vga_isa.c
index 033882d9713e..594e3d04c14b 100644
--- a/sys/isa/vga_isa.c
+++ b/sys/isa/vga_isa.c
@@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/malloc.h>
 #include <sys/module.h>
 #include <sys/conf.h>
 #include <sys/bus.h>
@@ -159,6 +160,58 @@ isavga_attach(device_t dev)
 	return 0;
 }
 
+static int
+isavga_suspend(device_t dev)
+{
+	vga_softc_t *sc;
+	int err, nbytes;
+
+	sc = device_get_softc(dev);
+	err = bus_generic_suspend(dev);
+	if (err)
+		return (err);
+
+	/* Save the video state across the suspend. */
+	if (sc->state_buf != NULL) {
+		free(sc->state_buf, M_TEMP);
+		sc->state_buf = NULL;
+	}
+	nbytes = (*vidsw[sc->adp->va_index]->save_state)(sc->adp, NULL, 0);
+	if (nbytes <= 0)
+		return (0);
+	sc->state_buf = malloc(nbytes, M_TEMP, M_NOWAIT | M_ZERO);
+	if (sc->state_buf == NULL)
+		return (0);
+	if (bootverbose)
+		device_printf(dev, "saving %d bytes of video state\n", nbytes);
+	if ((*vidsw[sc->adp->va_index]->save_state)(sc->adp, sc->state_buf,
+	    nbytes) != 0) {
+		device_printf(dev, "failed to save state (nbytes=%d)\n",
+		    nbytes);
+		free(sc->state_buf, M_TEMP);
+		sc->state_buf = NULL;
+	}
+	return (0);
+}
+
+static int
+isavga_resume(device_t dev)
+{
+	vga_softc_t *sc;
+
+	sc = device_get_softc(dev);
+	if (sc->state_buf != NULL) {
+		if ((*vidsw[sc->adp->va_index]->load_state)(sc->adp,
+		    sc->state_buf) != 0)
+			device_printf(dev, "failed to reload state\n");
+		free(sc->state_buf, M_TEMP);
+		sc->state_buf = NULL;
+	}
+
+	bus_generic_resume(dev);
+	return 0;
+}
+
 #ifdef FB_INSTALL_CDEV
 
 static int
@@ -203,6 +256,8 @@ static device_method_t isavga_methods[] = {
 	DEVMETHOD(device_identify,	isavga_identify),
 	DEVMETHOD(device_probe,		isavga_probe),
 	DEVMETHOD(device_attach,	isavga_attach),
+	DEVMETHOD(device_suspend,	isavga_suspend),
+	DEVMETHOD(device_resume,	isavga_resume),
 
 	DEVMETHOD(bus_print_child,	bus_generic_print_child),
 	{ 0, 0 }