From aa7c1c059f271ed89972971fae505aa4f23208bd Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Sat, 23 Aug 2008 21:00:40 +0000 Subject: [PATCH] Add a very simple dpms(4) driver that uses the VESA BIOS DPMS calls to turn off the external display during suspend and restore it to its original state on resume. MFC after: 2 weeks --- share/man/man4/man4.i386/Makefile | 1 + share/man/man4/man4.i386/dpms.4 | 58 ++++++++ sys/conf/files.i386 | 1 + sys/i386/conf/NOTES | 2 + sys/i386/isa/dpms.c | 230 ++++++++++++++++++++++++++++++ sys/modules/Makefile | 2 + sys/modules/dpms/Makefile | 9 ++ 7 files changed, 303 insertions(+) create mode 100644 share/man/man4/man4.i386/dpms.4 create mode 100644 sys/i386/isa/dpms.c create mode 100644 sys/modules/dpms/Makefile diff --git a/share/man/man4/man4.i386/Makefile b/share/man/man4/man4.i386/Makefile index 89eba8595dee..6d5a44e16e20 100644 --- a/share/man/man4/man4.i386/Makefile +++ b/share/man/man4/man4.i386/Makefile @@ -11,6 +11,7 @@ MAN= aic.4 \ cs.4 \ ct.4 \ ctau.4 \ + dpms.4 \ cx.4 \ ep.4 \ ex.4 \ diff --git a/share/man/man4/man4.i386/dpms.4 b/share/man/man4/man4.i386/dpms.4 new file mode 100644 index 000000000000..2412b47924ed --- /dev/null +++ b/share/man/man4/man4.i386/dpms.4 @@ -0,0 +1,58 @@ +.\" Copyright (c) 2008 Yahoo!, Inc. +.\" All rights reserved. +.\" Written by: John Baldwin +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the author nor the names of any co-contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd August 23, 2008 +.Dt DPMS 4 +.Os +.Sh NAME +.Nm dpms +.Nd VESA BIOS DPMS driver +.Sh SYNOPSIS +.Cd "device dpms" +.Sh DESCRIPTION +The +.Nm +driver uses the VESA BIOS to manage an external display during suspend and +resume. +When the machine suspends, +the +.Nm +driver turns the external display off. +When the machine resumes, +it restores the display to its state when the driver was first loaded. +.Sh SEE ALSO +.Xr acpi_video 4 +.Sh BUGS +.Pp +The VESA BIOS DPMS calls do not provide any way to identify a particular +display or adapter to manipulate. +As a result, +this driver may have unexpected results on systems with multiple displays +and/or adapters. diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index 4e854f4fa66d..0b9e3630fd66 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -329,6 +329,7 @@ i386/isa/atpic.c optional atpic #i386/isa/atpic_vector.s standard i386/isa/clock.c optional native i386/xen/clock.c optional xen +i386/isa/dpms.c optional dpms i386/isa/elcr.c standard i386/isa/elink.c optional ep | ie i386/isa/isa.c optional isa diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES index 17753363988d..a7458f4b2d2d 100644 --- a/sys/i386/conf/NOTES +++ b/sys/i386/conf/NOTES @@ -357,6 +357,8 @@ options VESA # Turn on extra debugging checks and output for VESA support. options VESA_DEBUG +device dpms # DPMS suspend & resume via VESA BIOS + # # The Numeric Processing eXtension driver. This is non-optional. device npx diff --git a/sys/i386/isa/dpms.c b/sys/i386/isa/dpms.c new file mode 100644 index 000000000000..723a6c05a3a3 --- /dev/null +++ b/sys/i386/isa/dpms.c @@ -0,0 +1,230 @@ +/*- + * Copyright (c) 2008 Yahoo!, Inc. + * All rights reserved. + * Written by: John Baldwin + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 2004 Benjamin Close + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Support for managing the display via DPMS for suspend/resume. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include + +/* + * VESA DPMS States + */ +#define DPMS_ON 0x00 +#define DPMS_STANDBY 0x01 +#define DPMS_SUSPEND 0x02 +#define DPMS_OFF 0x04 +#define DPMS_REDUCEDON 0x08 + +#define VBE_DPMS_FUNCTION 0x4F10 +#define VBE_DPMS_GET_SUPPORTED_STATES 0x00 +#define VBE_DPMS_GET_STATE 0x02 +#define VBE_DPMS_SET_STATE 0x01 +#define VBE_MAJORVERSION_MASK 0x0F +#define VBE_MINORVERSION_MASK 0xF0 + +struct dpms_softc { + int dpms_supported_states; + int dpms_initial_state; +}; + +static int dpms_attach(device_t); +static int dpms_detach(device_t); +static int dpms_get_supported_states(int *); +static int dpms_get_current_state(int *); +static void dpms_identify(driver_t *, device_t); +static int dpms_probe(device_t); +static int dpms_resume(device_t); +static int dpms_set_state(int); +static int dpms_suspend(device_t); + +static device_method_t dpms_methods[] = { + DEVMETHOD(device_identify, dpms_identify), + DEVMETHOD(device_probe, dpms_probe), + DEVMETHOD(device_attach, dpms_attach), + DEVMETHOD(device_detach, dpms_detach), + DEVMETHOD(device_suspend, dpms_suspend), + DEVMETHOD(device_resume, dpms_resume), + { 0, 0 } +}; + +static driver_t dpms_driver = { + "dpms", + dpms_methods, + sizeof(struct dpms_softc), +}; + +static devclass_t dpms_devclass; + +DRIVER_MODULE(dpms, vgapci, dpms_driver, dpms_devclass, NULL, NULL); + +static void +dpms_identify(driver_t *driver, device_t parent) +{ + + /* + * XXX: The DPMS VBE only allows for manipulating a single + * monitor, but we don't know which one. Just attach to the + * first vgapci(4) device we encounter and hope it is the + * right one. + */ + if (devclass_get_device(dpms_devclass, 0) == NULL) + device_add_child(parent, "dpms", 0); +} + +static int +dpms_probe(device_t dev) +{ + int error, states; + + error = dpms_get_supported_states(&states); + if (error) + return (error); + device_set_desc(dev, "DPMS suspend/resume"); + device_quiet(dev); + return (BUS_PROBE_DEFAULT); +} + +static int +dpms_attach(device_t dev) +{ + struct dpms_softc *sc; + int error; + + sc = device_get_softc(dev); + error = dpms_get_supported_states(&sc->dpms_supported_states); + if (error) + return (error); + error = dpms_get_current_state(&sc->dpms_initial_state); + return (error); +} + +static int +dpms_detach(device_t dev) +{ + + return (0); +} + +static int +dpms_suspend(device_t dev) +{ + + dpms_set_state(DPMS_OFF); + return (0); +} + +static int +dpms_resume(device_t dev) +{ + struct dpms_softc *sc; + + sc = device_get_softc(dev); + dpms_set_state(sc->dpms_initial_state); + return (0); +} + +static int +dpms_call_bios(int subfunction, int *bh) +{ + struct vm86frame vmf; + int error; + + bzero(&vmf, sizeof(vmf)); + vmf.vmf_ax = VBE_DPMS_FUNCTION; + vmf.vmf_bl = subfunction; + vmf.vmf_bh = *bh; + vmf.vmf_es = 0; + vmf.vmf_di = 0; + error = vm86_intcall(0x10, &vmf); + if (error == 0 && (vmf.vmf_eax & 0xffff) != 0x004f) + error = ENXIO; + if (error == 0) + *bh = vmf.vmf_bh; + return (error); +} + +static int +dpms_get_supported_states(int *states) +{ + + *states = 0; + return (dpms_call_bios(VBE_DPMS_GET_SUPPORTED_STATES, states)); +} + +static int +dpms_get_current_state(int *state) +{ + + *state = 0; + return (dpms_call_bios(VBE_DPMS_GET_STATE, state)); +} + +static int +dpms_set_state(int state) +{ + + return (dpms_call_bios(VBE_DPMS_SET_STATE, &state)); +} diff --git a/sys/modules/Makefile b/sys/modules/Makefile index 1862a417fb7d..753ef12a7773 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -72,6 +72,7 @@ SUBDIR= ${_3dfx} \ dcons \ dcons_crom \ de \ + ${_dpms} \ ${_dpt} \ ${_drm} \ ${_dtrace} \ @@ -377,6 +378,7 @@ _cs= cs .if ${MK_CDDL} != "no" || defined(ALL_MODULES) _cyclic= cyclic .endif +_dpms= dpms _drm= drm .if ${MK_CDDL} != "no" || defined(ALL_MODULES) _dtrace= dtrace diff --git a/sys/modules/dpms/Makefile b/sys/modules/dpms/Makefile new file mode 100644 index 000000000000..a58072e994f8 --- /dev/null +++ b/sys/modules/dpms/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../i386/isa + +KMOD= dpms +SRCS= dpms.c +SRCS+= bus_if.h device_if.h + +.include