dpms.c revision 198251
1/*- 2 * Copyright (c) 2008 Yahoo!, Inc. 3 * All rights reserved. 4 * Written by: John Baldwin <jhb@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of the author nor the names of any co-contributors 15 * may be used to endorse or promote products derived from this software 16 * without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31/* 32 * Copyright (c) 2004 Benjamin Close <Benjamin.Close@clearchain.com> 33 * All rights reserved. 34 * 35 * Redistribution and use in source and binary forms, with or without 36 * modification, are permitted provided that the following conditions 37 * are met: 38 * 1. Redistributions of source code must retain the above copyright 39 * notice, this list of conditions and the following disclaimer. 40 * 2. Redistributions in binary form must reproduce the above copyright 41 * notice, this list of conditions and the following disclaimer in the 42 * documentation and/or other materials provided with the distribution. 43 * 44 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 47 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 54 * SUCH DAMAGE. 55 */ 56 57/* 58 * Support for managing the display via DPMS for suspend/resume. 59 */ 60 61#include <sys/cdefs.h> 62__FBSDID("$FreeBSD: head/sys/dev/dpms/dpms.c 198251 2009-10-19 20:58:10Z jkim $"); 63 64#include <sys/param.h> 65#include <sys/bus.h> 66#include <sys/kernel.h> 67#include <sys/libkern.h> 68#include <sys/module.h> 69 70#include <compat/x86bios/x86bios.h> 71 72/* 73 * VESA DPMS States 74 */ 75#define DPMS_ON 0x00 76#define DPMS_STANDBY 0x01 77#define DPMS_SUSPEND 0x02 78#define DPMS_OFF 0x04 79#define DPMS_REDUCEDON 0x08 80 81#define VBE_DPMS_FUNCTION 0x4F10 82#define VBE_DPMS_GET_SUPPORTED_STATES 0x00 83#define VBE_DPMS_GET_STATE 0x02 84#define VBE_DPMS_SET_STATE 0x01 85#define VBE_MAJORVERSION_MASK 0x0F 86#define VBE_MINORVERSION_MASK 0xF0 87 88struct dpms_softc { 89 int dpms_supported_states; 90 int dpms_initial_state; 91}; 92 93static int dpms_attach(device_t); 94static int dpms_detach(device_t); 95static int dpms_get_supported_states(int *); 96static int dpms_get_current_state(int *); 97static void dpms_identify(driver_t *, device_t); 98static int dpms_probe(device_t); 99static int dpms_resume(device_t); 100static int dpms_set_state(int); 101static int dpms_suspend(device_t); 102 103static device_method_t dpms_methods[] = { 104 DEVMETHOD(device_identify, dpms_identify), 105 DEVMETHOD(device_probe, dpms_probe), 106 DEVMETHOD(device_attach, dpms_attach), 107 DEVMETHOD(device_detach, dpms_detach), 108 DEVMETHOD(device_suspend, dpms_suspend), 109 DEVMETHOD(device_resume, dpms_resume), 110 { 0, 0 } 111}; 112 113static driver_t dpms_driver = { 114 "dpms", 115 dpms_methods, 116 sizeof(struct dpms_softc), 117}; 118 119static devclass_t dpms_devclass; 120 121DRIVER_MODULE(dpms, vgapci, dpms_driver, dpms_devclass, NULL, NULL); 122MODULE_DEPEND(dpms, x86bios, 1, 1, 1); 123 124static void 125dpms_identify(driver_t *driver, device_t parent) 126{ 127 128 /* The DPMS VBE only allows for manipulating a single monitor. */ 129 if (devclass_get_device(dpms_devclass, 0) != NULL) 130 return; 131 132 if ((x86bios_match_device(0xc0000, parent) && 133 device_get_flags(parent) != 0) || 134 x86bios_get_orm(0xc0000) != NULL) 135 device_add_child(parent, "dpms", 0); 136} 137 138static int 139dpms_probe(device_t dev) 140{ 141 int error, states; 142 143 error = dpms_get_supported_states(&states); 144 if (error) 145 return (error); 146 device_set_desc(dev, "DPMS suspend/resume"); 147 device_quiet(dev); 148 return (BUS_PROBE_DEFAULT); 149} 150 151static int 152dpms_attach(device_t dev) 153{ 154 struct dpms_softc *sc; 155 int error; 156 157 sc = device_get_softc(dev); 158 error = dpms_get_supported_states(&sc->dpms_supported_states); 159 if (error) 160 return (error); 161 error = dpms_get_current_state(&sc->dpms_initial_state); 162 return (error); 163} 164 165static int 166dpms_detach(device_t dev) 167{ 168 169 return (0); 170} 171 172static int 173dpms_suspend(device_t dev) 174{ 175 struct dpms_softc *sc; 176 177 sc = device_get_softc(dev); 178 if ((sc->dpms_supported_states & DPMS_OFF) != 0) 179 dpms_set_state(DPMS_OFF); 180 return (0); 181} 182 183static int 184dpms_resume(device_t dev) 185{ 186 struct dpms_softc *sc; 187 188 sc = device_get_softc(dev); 189 dpms_set_state(sc->dpms_initial_state); 190 return (0); 191} 192 193static int 194dpms_call_bios(int subfunction, int *bh) 195{ 196 x86regs_t regs; 197 198 if (x86bios_get_intr(0x10) == 0) 199 return (ENXIO); 200 201 x86bios_init_regs(®s); 202 regs.R_AX = VBE_DPMS_FUNCTION; 203 regs.R_BL = subfunction; 204 regs.R_BH = *bh; 205 x86bios_intr(®s, 0x10); 206 207 if (regs.R_AX != 0x004f) 208 return (ENXIO); 209 210 *bh = regs.R_BH; 211 212 return (0); 213} 214 215static int 216dpms_get_supported_states(int *states) 217{ 218 219 *states = 0; 220 return (dpms_call_bios(VBE_DPMS_GET_SUPPORTED_STATES, states)); 221} 222 223static int 224dpms_get_current_state(int *state) 225{ 226 227 *state = 0; 228 return (dpms_call_bios(VBE_DPMS_GET_STATE, state)); 229} 230 231static int 232dpms_set_state(int state) 233{ 234 235 return (dpms_call_bios(VBE_DPMS_SET_STATE, &state)); 236} 237