1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 2008 Yahoo!, Inc.
5 * All rights reserved.
6 * Written by: John Baldwin <[email protected]>
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 <[email protected]>
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 #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
88 struct dpms_softc {
89 int dpms_supported_states;
90 int dpms_initial_state;
91 };
92
93 static int dpms_attach(device_t);
94 static int dpms_detach(device_t);
95 static int dpms_get_supported_states(int *);
96 static int dpms_get_current_state(int *);
97 static void dpms_identify(driver_t *, device_t);
98 static int dpms_probe(device_t);
99 static int dpms_resume(device_t);
100 static int dpms_set_state(int);
101 static int dpms_suspend(device_t);
102
103 static 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
113 static driver_t dpms_driver = {
114 "dpms",
115 dpms_methods,
116 sizeof(struct dpms_softc),
117 };
118
119 DRIVER_MODULE(dpms, vgapm, dpms_driver, NULL, NULL);
120 MODULE_DEPEND(dpms, x86bios, 1, 1, 1);
121
122 static void
dpms_identify(driver_t * driver,device_t parent)123 dpms_identify(driver_t *driver, device_t parent)
124 {
125
126 if (x86bios_match_device(0xc0000, device_get_parent(parent)))
127 device_add_child(parent, "dpms", 0);
128 }
129
130 static int
dpms_probe(device_t dev)131 dpms_probe(device_t dev)
132 {
133 int error, states;
134
135 error = dpms_get_supported_states(&states);
136 if (error)
137 return (error);
138 device_set_desc(dev, "DPMS suspend/resume");
139 device_quiet(dev);
140 return (BUS_PROBE_DEFAULT);
141 }
142
143 static int
dpms_attach(device_t dev)144 dpms_attach(device_t dev)
145 {
146 struct dpms_softc *sc;
147 int error;
148
149 sc = device_get_softc(dev);
150 error = dpms_get_supported_states(&sc->dpms_supported_states);
151 if (error)
152 return (error);
153 error = dpms_get_current_state(&sc->dpms_initial_state);
154 return (error);
155 }
156
157 static int
dpms_detach(device_t dev)158 dpms_detach(device_t dev)
159 {
160
161 return (0);
162 }
163
164 static int
dpms_suspend(device_t dev)165 dpms_suspend(device_t dev)
166 {
167 struct dpms_softc *sc;
168
169 sc = device_get_softc(dev);
170 if ((sc->dpms_supported_states & DPMS_OFF) != 0)
171 dpms_set_state(DPMS_OFF);
172 return (0);
173 }
174
175 static int
dpms_resume(device_t dev)176 dpms_resume(device_t dev)
177 {
178 struct dpms_softc *sc;
179
180 sc = device_get_softc(dev);
181 dpms_set_state(sc->dpms_initial_state);
182 return (0);
183 }
184
185 static int
dpms_call_bios(int subfunction,int * bh)186 dpms_call_bios(int subfunction, int *bh)
187 {
188 x86regs_t regs;
189
190 if (x86bios_get_intr(0x10) == 0)
191 return (ENXIO);
192
193 x86bios_init_regs(®s);
194 regs.R_AX = VBE_DPMS_FUNCTION;
195 regs.R_BL = subfunction;
196 regs.R_BH = *bh;
197 x86bios_intr(®s, 0x10);
198
199 if (regs.R_AX != 0x004f)
200 return (ENXIO);
201
202 *bh = regs.R_BH;
203
204 return (0);
205 }
206
207 static int
dpms_get_supported_states(int * states)208 dpms_get_supported_states(int *states)
209 {
210
211 *states = 0;
212 return (dpms_call_bios(VBE_DPMS_GET_SUPPORTED_STATES, states));
213 }
214
215 static int
dpms_get_current_state(int * state)216 dpms_get_current_state(int *state)
217 {
218
219 *state = 0;
220 return (dpms_call_bios(VBE_DPMS_GET_STATE, state));
221 }
222
223 static int
dpms_set_state(int state)224 dpms_set_state(int state)
225 {
226
227 return (dpms_call_bios(VBE_DPMS_SET_STATE, &state));
228 }
229