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