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