Using VESA to restore display settings on resume

Ian Dowse iedowse at maths.tcd.ie
Sun Feb 27 04:31:27 GMT 2005


It's possible that the experimantal patch below may help on some
notebooks where the display does not recover from a suspend-resume
cycle. It makes use of the VESA BIOS to save the display settings
before the system suspends and then restores them on resume. The
patch is against -CURRENT, but might apply against RELENG_5 without
too much trouble.

I have a JVC laptop here where this is the only way I have found
so far to bring the LCD back to life after resuming, so maybe it
will help on other systems too.

To test it, apply the patch and rebuild your kernel + modules. You
need to either have 'options VESA' in the kernel config or else
load the vesa module. It may also be worth trying with the
hw.acpi.reset_video sysctl set to 0, since rerunning the VGA POST
should be unnecessary.

Ian

Patch also at: http://people.freebsd.org/~iedowse/vesa_restore.diff

Index: dev/fb/vgareg.h
===================================================================
RCS file: /dump/FreeBSD-CVS/src/sys/dev/fb/vgareg.h,v
retrieving revision 1.7
diff -u -r1.7 vgareg.h
--- dev/fb/vgareg.h	16 Jun 2004 09:46:43 -0000	1.7
+++ dev/fb/vgareg.h	27 Feb 2005 02:37:20 -0000
@@ -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
Index: isa/vga_isa.c
===================================================================
RCS file: /dump/FreeBSD-CVS/src/sys/isa/vga_isa.c,v
retrieving revision 1.31
diff -u -r1.31 vga_isa.c
--- isa/vga_isa.c	3 Nov 2004 09:07:44 -0000	1.31
+++ isa/vga_isa.c	27 Feb 2005 03:12:08 -0000
@@ -34,6 +34,7 @@
 #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>
@@ -160,6 +161,55 @@
 	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 ((*vidsw[sc->adp->va_index]->save_state)(sc->adp, sc->state_buf,
+	    nbytes) != 0) {
+		device_printf(dev, "failed to save state\n");
+		free(sc->state_buf, M_TEMP);
+		sc->state_buf = NULL;
+	} else 
+		device_printf(dev, "saved %d bytes of state\n", nbytes);
+	return (0);
+}
+
+static int
+isavga_resume(device_t dev)
+{
+	vga_softc_t *sc;
+
+	sc = device_get_softc(dev);
+	if (sc->state_buf != NULL) {
+		device_printf(dev, "restoring state\n");
+		(*vidsw[sc->adp->va_index]->load_state)(sc->adp, sc->state_buf);
+		free(sc->state_buf, M_TEMP);
+		sc->state_buf = NULL;
+	}
+
+	bus_generic_resume(dev);
+	return 0;
+}
+
 #ifdef FB_INSTALL_CDEV
 
 static int
@@ -204,6 +254,8 @@
 	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 }
Index: i386/isa/vesa.c
===================================================================
RCS file: /dump/FreeBSD-CVS/src/sys/i386/isa/vesa.c,v
retrieving revision 1.47
diff -u -r1.47 vesa.c
--- i386/isa/vesa.c	15 Jul 2004 08:26:05 -0000	1.47
+++ i386/isa/vesa.c	27 Feb 2005 03:54:02 -0000
@@ -423,7 +423,7 @@
 
 	bzero(&vmf, sizeof(vmf));
 	vmf.vmf_eax = 0x4f04; 
-	vmf.vmf_ecx = STATE_MOST;
+	vmf.vmf_ecx = STATE_ALL;
 	vmf.vmf_edx = STATE_SIZE;
 	err = vm86_intcall(0x10, &vmf);
 	if ((err != 0) || (vmf.vmf_ax != 0x4f))
@@ -440,13 +440,14 @@
 
 	bzero(&vmf, sizeof(vmf));
 	vmf.vmf_eax = 0x4f04; 
-	vmf.vmf_ecx = STATE_MOST;
+	vmf.vmf_ecx = STATE_ALL;
 	vmf.vmf_edx = code;	/* STATE_SAVE/STATE_LOAD */
 	buf = (u_char *)vm86_getpage(&vesa_vmcontext, 1);
 	vm86_getptr(&vesa_vmcontext, (vm_offset_t)buf, &vmf.vmf_es, &vmf.vmf_bx);
 	bcopy(p, buf, size);
 
 	err = vm86_datacall(0x10, &vmf, &vesa_vmcontext);
+	bcopy(buf, p, size);
 	return ((err != 0) || (vmf.vmf_ax != 0x4f));
 }




More information about the freebsd-mobile mailing list