dpms.c revision 199230
1139749Simp/*-
21817Sdg * Copyright (c) 2008 Yahoo!, Inc.
31817Sdg * All rights reserved.
41817Sdg * Written by: John Baldwin <jhb@FreeBSD.org>
51817Sdg *
61817Sdg * Redistribution and use in source and binary forms, with or without
71817Sdg * modification, are permitted provided that the following conditions
81817Sdg * are met:
950477Speter * 1. Redistributions of source code must retain the above copyright
101817Sdg *    notice, this list of conditions and the following disclaimer.
111817Sdg * 2. Redistributions in binary form must reproduce the above copyright
128876Srgrimes *    notice, this list of conditions and the following disclaimer in the
1343Sdg *    documentation and/or other materials provided with the distribution.
14498Sdg * 3. Neither the name of the author nor the names of any co-contributors
15498Sdg *    may be used to endorse or promote products derived from this software
16498Sdg *    without specific prior written permission.
17808Sdg *
18808Sdg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19808Sdg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20808Sdg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21791Sdg * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22791Sdg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23791Sdg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24791Sdg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25520Sdg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26520Sdg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27520Sdg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28520Sdg * SUCH DAMAGE.
298876Srgrimes */
3043Sdg
3143Sdg/*
328876Srgrimes * Copyright (c) 2004 Benjamin Close <Benjamin.Close@clearchain.com>
336Sdg * All rights reserved.
346Sdg *
356Sdg * Redistribution and use in source and binary forms, with or without
366Sdg * modification, are permitted provided that the following conditions
376Sdg * are met:
386Sdg * 1. Redistributions of source code must retain the above copyright
396Sdg *    notice, this list of conditions and the following disclaimer.
406Sdg * 2. Redistributions in binary form must reproduce the above copyright
416Sdg *    notice, this list of conditions and the following disclaimer in the
426Sdg *    documentation and/or other materials provided with the distribution.
436Sdg *
446Sdg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
456Sdg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
466Sdg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
476Sdg * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
486Sdg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
496Sdg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
506Sdg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
516Sdg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
526Sdg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
536Sdg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
546Sdg * SUCH DAMAGE.
556Sdg */
566Sdg
576Sdg/*
586Sdg * Support for managing the display via DPMS for suspend/resume.
596Sdg */
606Sdg
616Sdg#include <sys/cdefs.h>
626Sdg__FBSDID("$FreeBSD: head/sys/dev/dpms/dpms.c 199230 2009-11-12 18:16:35Z jkim $");
636Sdg
646Sdg#include <sys/param.h>
656Sdg#include <sys/bus.h>
666Sdg#include <sys/kernel.h>
676Sdg#include <sys/libkern.h>
686Sdg#include <sys/module.h>
696Sdg
706Sdg#include <compat/x86bios/x86bios.h>
716Sdg
726Sdg/*
736Sdg * VESA DPMS States
746Sdg */
756Sdg#define DPMS_ON		0x00
766Sdg#define DPMS_STANDBY	0x01
776Sdg#define DPMS_SUSPEND	0x02
786Sdg#define DPMS_OFF	0x04
796Sdg#define DPMS_REDUCEDON	0x08
806Sdg
816Sdg#define	VBE_DPMS_FUNCTION	0x4F10
826Sdg#define	VBE_DPMS_GET_SUPPORTED_STATES 0x00
836Sdg#define	VBE_DPMS_GET_STATE	0x02
846Sdg#define	VBE_DPMS_SET_STATE	0x01
856Sdg#define VBE_MAJORVERSION_MASK	0x0F
866Sdg#define VBE_MINORVERSION_MASK	0xF0
876Sdg
886Sdgstruct dpms_softc {
896Sdg	int	dpms_supported_states;
906Sdg	int	dpms_initial_state;
9150808Skato};
926Sdg
936Sdgstatic int	dpms_attach(device_t);
946Sdgstatic int	dpms_detach(device_t);
956Sdgstatic int	dpms_get_supported_states(int *);
966Sdgstatic int	dpms_get_current_state(int *);
976Sdgstatic void	dpms_identify(driver_t *, device_t);
986Sdgstatic int	dpms_probe(device_t);
996Sdgstatic int	dpms_resume(device_t);
1006Sdgstatic int	dpms_set_state(int);
10150808Skatostatic int	dpms_suspend(device_t);
1026Sdg
1036Sdgstatic device_method_t dpms_methods[] = {
1046Sdg	DEVMETHOD(device_identify,	dpms_identify),
1056Sdg	DEVMETHOD(device_probe,		dpms_probe),
1066Sdg	DEVMETHOD(device_attach,	dpms_attach),
1076Sdg	DEVMETHOD(device_detach,	dpms_detach),
1086Sdg	DEVMETHOD(device_suspend,	dpms_suspend),
1096Sdg	DEVMETHOD(device_resume,	dpms_resume),
1106Sdg	{ 0, 0 }
1116Sdg};
1126Sdg
1136Sdgstatic driver_t dpms_driver = {
1146Sdg	"dpms",
1156Sdg	dpms_methods,
1166Sdg	sizeof(struct dpms_softc),
1176Sdg};
1186Sdg
1196Sdgstatic devclass_t dpms_devclass;
1206Sdg
1216SdgDRIVER_MODULE(dpms, vgapci, dpms_driver, dpms_devclass, NULL, NULL);
1226SdgMODULE_DEPEND(dpms, x86bios, 1, 1, 1);
1236Sdg
1246Sdgstatic void
1256Sdgdpms_identify(driver_t *driver, device_t parent)
1266Sdg{
1276Sdg
1286Sdg	if (device_get_flags(parent) != 0 &&
1296Sdg	    x86bios_match_device(0xc0000, parent))
1306Sdg		device_add_child(parent, "dpms", 0);
1316Sdg}
1326Sdg
1336Sdgstatic int
1346Sdgdpms_probe(device_t dev)
1356Sdg{
1366Sdg	int error, states;
1376Sdg
1386Sdg	error = dpms_get_supported_states(&states);
1396Sdg	if (error)
1406Sdg		return (error);
1416Sdg	device_set_desc(dev, "DPMS suspend/resume");
1426Sdg	device_quiet(dev);
1436Sdg	return (BUS_PROBE_DEFAULT);
1446Sdg}
1456Sdg
1466Sdgstatic int
1476Sdgdpms_attach(device_t dev)
1486Sdg{
1496Sdg	struct dpms_softc *sc;
1506Sdg	int error;
1516Sdg
1526Sdg	sc = device_get_softc(dev);
1536Sdg	error = dpms_get_supported_states(&sc->dpms_supported_states);
1546Sdg	if (error)
1556Sdg		return (error);
1566Sdg	error = dpms_get_current_state(&sc->dpms_initial_state);
1576Sdg	return (error);
1586Sdg}
1596Sdg
1606Sdgstatic int
1616Sdgdpms_detach(device_t dev)
1626Sdg{
1636Sdg
1646Sdg	return (0);
1656Sdg}
1666Sdg
1676Sdgstatic int
1686Sdgdpms_suspend(device_t dev)
1696Sdg{
1706Sdg	struct dpms_softc *sc;
1716Sdg
1726Sdg	sc = device_get_softc(dev);
1736Sdg	if ((sc->dpms_supported_states & DPMS_OFF) != 0)
1746Sdg		dpms_set_state(DPMS_OFF);
1756Sdg	return (0);
1766Sdg}
177150957Simp
1786Sdgstatic int
1796Sdgdpms_resume(device_t dev)
1806Sdg{
1816Sdg	struct dpms_softc *sc;
1826Sdg
1836Sdg	sc = device_get_softc(dev);
1846Sdg	dpms_set_state(sc->dpms_initial_state);
185150957Simp	return (0);
1866Sdg}
1876Sdg
1886Sdgstatic int
1896Sdgdpms_call_bios(int subfunction, int *bh)
1906Sdg{
1916Sdg	x86regs_t regs;
1926Sdg
1936Sdg	if (x86bios_get_intr(0x10) == 0)
1946Sdg		return (ENXIO);
1956Sdg
1966Sdg	x86bios_init_regs(&regs);
1976Sdg	regs.R_AX = VBE_DPMS_FUNCTION;
1986Sdg	regs.R_BL = subfunction;
1996Sdg	regs.R_BH = *bh;
2006Sdg	x86bios_intr(&regs, 0x10);
2016Sdg
2026Sdg	if (regs.R_AX != 0x004f)
2036Sdg		return (ENXIO);
2046Sdg
2056Sdg	*bh = regs.R_BH;
2066Sdg
2076Sdg	return (0);
2086Sdg}
2096Sdg
2106Sdgstatic int
2116Sdgdpms_get_supported_states(int *states)
2126Sdg{
2136Sdg
2146Sdg	*states = 0;
2156Sdg	return (dpms_call_bios(VBE_DPMS_GET_SUPPORTED_STATES, states));
2166Sdg}
21713765Smpp
2186Sdgstatic int
2196Sdgdpms_get_current_state(int *state)
2206Sdg{
2216Sdg
2226Sdg	*state = 0;
2236Sdg	return (dpms_call_bios(VBE_DPMS_GET_STATE, state));
2246Sdg}
2256Sdg
2266Sdgstatic int
2276Sdgdpms_set_state(int state)
2286Sdg{
2296Sdg
2306Sdg	return (dpms_call_bios(VBE_DPMS_SET_STATE, &state));
2316Sdg}
2326Sdg