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