dpms.c revision 197444
1182081Sjhb/*- 2182081Sjhb * Copyright (c) 2008 Yahoo!, Inc. 3182081Sjhb * All rights reserved. 4182081Sjhb * Written by: John Baldwin <jhb@FreeBSD.org> 5182081Sjhb * 6182081Sjhb * Redistribution and use in source and binary forms, with or without 7182081Sjhb * modification, are permitted provided that the following conditions 8182081Sjhb * are met: 9182081Sjhb * 1. Redistributions of source code must retain the above copyright 10182081Sjhb * notice, this list of conditions and the following disclaimer. 11182081Sjhb * 2. Redistributions in binary form must reproduce the above copyright 12182081Sjhb * notice, this list of conditions and the following disclaimer in the 13182081Sjhb * documentation and/or other materials provided with the distribution. 14182081Sjhb * 3. Neither the name of the author nor the names of any co-contributors 15182081Sjhb * may be used to endorse or promote products derived from this software 16182081Sjhb * without specific prior written permission. 17182081Sjhb * 18182081Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19182081Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20182081Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21182081Sjhb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22182081Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23182081Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24182081Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25182081Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26182081Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27182081Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28182081Sjhb * SUCH DAMAGE. 29182081Sjhb */ 30182081Sjhb 31182081Sjhb/* 32182081Sjhb * Copyright (c) 2004 Benjamin Close <Benjamin.Close@clearchain.com> 33182081Sjhb * All rights reserved. 34182081Sjhb * 35182081Sjhb * Redistribution and use in source and binary forms, with or without 36182081Sjhb * modification, are permitted provided that the following conditions 37182081Sjhb * are met: 38182081Sjhb * 1. Redistributions of source code must retain the above copyright 39182081Sjhb * notice, this list of conditions and the following disclaimer. 40182081Sjhb * 2. Redistributions in binary form must reproduce the above copyright 41182081Sjhb * notice, this list of conditions and the following disclaimer in the 42182081Sjhb * documentation and/or other materials provided with the distribution. 43182081Sjhb * 44182081Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 45182081Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 46182081Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 47182081Sjhb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 48182081Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 49182081Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 50182081Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 51182081Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 52182081Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 53182081Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 54182081Sjhb * SUCH DAMAGE. 55182081Sjhb */ 56182081Sjhb 57182081Sjhb/* 58182081Sjhb * Support for managing the display via DPMS for suspend/resume. 59182081Sjhb */ 60182081Sjhb 61182081Sjhb#include <sys/cdefs.h> 62182081Sjhb__FBSDID("$FreeBSD: head/sys/dev/dpms/dpms.c 197444 2009-09-23 20:49:14Z jkim $"); 63182081Sjhb 64182081Sjhb#include <sys/param.h> 65182081Sjhb#include <sys/bus.h> 66182081Sjhb#include <sys/kernel.h> 67182081Sjhb#include <sys/libkern.h> 68182081Sjhb#include <sys/module.h> 69182081Sjhb 70197444Sjkim#include <compat/x86bios/x86bios.h> 71182081Sjhb 72182081Sjhb/* 73182081Sjhb * VESA DPMS States 74182081Sjhb */ 75182081Sjhb#define DPMS_ON 0x00 76182081Sjhb#define DPMS_STANDBY 0x01 77182081Sjhb#define DPMS_SUSPEND 0x02 78182081Sjhb#define DPMS_OFF 0x04 79182081Sjhb#define DPMS_REDUCEDON 0x08 80182081Sjhb 81182081Sjhb#define VBE_DPMS_FUNCTION 0x4F10 82182081Sjhb#define VBE_DPMS_GET_SUPPORTED_STATES 0x00 83182081Sjhb#define VBE_DPMS_GET_STATE 0x02 84182081Sjhb#define VBE_DPMS_SET_STATE 0x01 85182081Sjhb#define VBE_MAJORVERSION_MASK 0x0F 86182081Sjhb#define VBE_MINORVERSION_MASK 0xF0 87182081Sjhb 88182081Sjhbstruct dpms_softc { 89182081Sjhb int dpms_supported_states; 90182081Sjhb int dpms_initial_state; 91182081Sjhb}; 92182081Sjhb 93182081Sjhbstatic int dpms_attach(device_t); 94182081Sjhbstatic int dpms_detach(device_t); 95182081Sjhbstatic int dpms_get_supported_states(int *); 96182081Sjhbstatic int dpms_get_current_state(int *); 97182081Sjhbstatic void dpms_identify(driver_t *, device_t); 98182081Sjhbstatic int dpms_probe(device_t); 99182081Sjhbstatic int dpms_resume(device_t); 100182081Sjhbstatic int dpms_set_state(int); 101182081Sjhbstatic int dpms_suspend(device_t); 102182081Sjhb 103182081Sjhbstatic device_method_t dpms_methods[] = { 104182081Sjhb DEVMETHOD(device_identify, dpms_identify), 105182081Sjhb DEVMETHOD(device_probe, dpms_probe), 106182081Sjhb DEVMETHOD(device_attach, dpms_attach), 107182081Sjhb DEVMETHOD(device_detach, dpms_detach), 108182081Sjhb DEVMETHOD(device_suspend, dpms_suspend), 109182081Sjhb DEVMETHOD(device_resume, dpms_resume), 110182081Sjhb { 0, 0 } 111182081Sjhb}; 112182081Sjhb 113182081Sjhbstatic driver_t dpms_driver = { 114182081Sjhb "dpms", 115182081Sjhb dpms_methods, 116182081Sjhb sizeof(struct dpms_softc), 117182081Sjhb}; 118182081Sjhb 119182081Sjhbstatic devclass_t dpms_devclass; 120182081Sjhb 121182081SjhbDRIVER_MODULE(dpms, vgapci, dpms_driver, dpms_devclass, NULL, NULL); 122197383SdelphijMODULE_DEPEND(dpms, x86bios, 1, 1, 1); 123182081Sjhb 124182081Sjhbstatic void 125182081Sjhbdpms_identify(driver_t *driver, device_t parent) 126182081Sjhb{ 127182081Sjhb 128182081Sjhb /* 129182081Sjhb * XXX: The DPMS VBE only allows for manipulating a single 130182081Sjhb * monitor, but we don't know which one. Just attach to the 131182081Sjhb * first vgapci(4) device we encounter and hope it is the 132182081Sjhb * right one. 133182081Sjhb */ 134182081Sjhb if (devclass_get_device(dpms_devclass, 0) == NULL) 135182081Sjhb device_add_child(parent, "dpms", 0); 136182081Sjhb} 137182081Sjhb 138182081Sjhbstatic int 139182081Sjhbdpms_probe(device_t dev) 140182081Sjhb{ 141182081Sjhb int error, states; 142182081Sjhb 143182081Sjhb error = dpms_get_supported_states(&states); 144182081Sjhb if (error) 145182081Sjhb return (error); 146182081Sjhb device_set_desc(dev, "DPMS suspend/resume"); 147182081Sjhb device_quiet(dev); 148182081Sjhb return (BUS_PROBE_DEFAULT); 149182081Sjhb} 150182081Sjhb 151182081Sjhbstatic int 152182081Sjhbdpms_attach(device_t dev) 153182081Sjhb{ 154182081Sjhb struct dpms_softc *sc; 155182081Sjhb int error; 156182081Sjhb 157182081Sjhb sc = device_get_softc(dev); 158182081Sjhb error = dpms_get_supported_states(&sc->dpms_supported_states); 159182081Sjhb if (error) 160182081Sjhb return (error); 161182081Sjhb error = dpms_get_current_state(&sc->dpms_initial_state); 162182081Sjhb return (error); 163182081Sjhb} 164182081Sjhb 165182081Sjhbstatic int 166182081Sjhbdpms_detach(device_t dev) 167182081Sjhb{ 168182081Sjhb 169182081Sjhb return (0); 170182081Sjhb} 171182081Sjhb 172182081Sjhbstatic int 173182081Sjhbdpms_suspend(device_t dev) 174182081Sjhb{ 175182081Sjhb 176182081Sjhb dpms_set_state(DPMS_OFF); 177182081Sjhb return (0); 178182081Sjhb} 179182081Sjhb 180182081Sjhbstatic int 181182081Sjhbdpms_resume(device_t dev) 182182081Sjhb{ 183182081Sjhb struct dpms_softc *sc; 184182081Sjhb 185182081Sjhb sc = device_get_softc(dev); 186182081Sjhb dpms_set_state(sc->dpms_initial_state); 187182081Sjhb return (0); 188182081Sjhb} 189182081Sjhb 190182081Sjhbstatic int 191182081Sjhbdpms_call_bios(int subfunction, int *bh) 192182081Sjhb{ 193197383Sdelphij x86regs_t regs; 194182081Sjhb 195197383Sdelphij regs.R_AX = VBE_DPMS_FUNCTION; 196197383Sdelphij regs.R_BL = subfunction; 197197383Sdelphij regs.R_BH = *bh; 198197383Sdelphij regs.R_ES = 0; 199197383Sdelphij regs.R_DI = 0; 200197383Sdelphij x86biosCall(®s, 0x10); 201197383Sdelphij 202197383Sdelphij if ((regs.R_EAX & 0xffff) != 0x004f) 203197025Sdelphij return (ENXIO); 204197025Sdelphij 205197383Sdelphij *bh = regs.R_BH; 206197025Sdelphij 207197025Sdelphij return (0); 208182081Sjhb} 209182081Sjhb 210182081Sjhbstatic int 211182081Sjhbdpms_get_supported_states(int *states) 212182081Sjhb{ 213182081Sjhb 214182081Sjhb *states = 0; 215182081Sjhb return (dpms_call_bios(VBE_DPMS_GET_SUPPORTED_STATES, states)); 216182081Sjhb} 217182081Sjhb 218182081Sjhbstatic int 219182081Sjhbdpms_get_current_state(int *state) 220182081Sjhb{ 221182081Sjhb 222182081Sjhb *state = 0; 223182081Sjhb return (dpms_call_bios(VBE_DPMS_GET_STATE, state)); 224182081Sjhb} 225182081Sjhb 226182081Sjhbstatic int 227182081Sjhbdpms_set_state(int state) 228182081Sjhb{ 229182081Sjhb 230182081Sjhb return (dpms_call_bios(VBE_DPMS_SET_STATE, &state)); 231182081Sjhb} 232