kern_pmf.c revision 1.10.2.2 1 1.10.2.2 matt /* $NetBSD: kern_pmf.c,v 1.10.2.2 2008/01/09 01:56:06 matt Exp $ */
2 1.10.2.2 matt
3 1.10.2.2 matt /*-
4 1.10.2.2 matt * Copyright (c) 2007 Jared D. McNeill <jmcneill (at) invisible.ca>
5 1.10.2.2 matt * All rights reserved.
6 1.10.2.2 matt *
7 1.10.2.2 matt * Redistribution and use in source and binary forms, with or without
8 1.10.2.2 matt * modification, are permitted provided that the following conditions
9 1.10.2.2 matt * are met:
10 1.10.2.2 matt * 1. Redistributions of source code must retain the above copyright
11 1.10.2.2 matt * notice, this list of conditions and the following disclaimer.
12 1.10.2.2 matt * 2. Redistributions in binary form must reproduce the above copyright
13 1.10.2.2 matt * notice, this list of conditions and the following disclaimer in the
14 1.10.2.2 matt * documentation and/or other materials provided with the distribution.
15 1.10.2.2 matt * 3. All advertising materials mentioning features or use of this software
16 1.10.2.2 matt * must display the following acknowledgement:
17 1.10.2.2 matt * This product includes software developed by Jared D. McNeill.
18 1.10.2.2 matt * 4. Neither the name of The NetBSD Foundation nor the names of its
19 1.10.2.2 matt * contributors may be used to endorse or promote products derived
20 1.10.2.2 matt * from this software without specific prior written permission.
21 1.10.2.2 matt *
22 1.10.2.2 matt * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23 1.10.2.2 matt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24 1.10.2.2 matt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 1.10.2.2 matt * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26 1.10.2.2 matt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 1.10.2.2 matt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 1.10.2.2 matt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 1.10.2.2 matt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 1.10.2.2 matt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 1.10.2.2 matt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 1.10.2.2 matt * POSSIBILITY OF SUCH DAMAGE.
33 1.10.2.2 matt */
34 1.10.2.2 matt
35 1.10.2.2 matt #include <sys/cdefs.h>
36 1.10.2.2 matt __KERNEL_RCSID(0, "$NetBSD: kern_pmf.c,v 1.10.2.2 2008/01/09 01:56:06 matt Exp $");
37 1.10.2.2 matt
38 1.10.2.2 matt #include <sys/types.h>
39 1.10.2.2 matt #include <sys/param.h>
40 1.10.2.2 matt #include <sys/malloc.h>
41 1.10.2.2 matt #include <sys/buf.h>
42 1.10.2.2 matt #include <sys/callout.h>
43 1.10.2.2 matt #include <sys/kernel.h>
44 1.10.2.2 matt #include <sys/device.h>
45 1.10.2.2 matt #include <sys/pmf.h>
46 1.10.2.2 matt #include <sys/queue.h>
47 1.10.2.2 matt #include <sys/syscallargs.h> /* for sys_sync */
48 1.10.2.2 matt #include <sys/workqueue.h>
49 1.10.2.2 matt #include <prop/proplib.h>
50 1.10.2.2 matt
51 1.10.2.2 matt #ifdef PMF_DEBUG
52 1.10.2.2 matt int pmf_debug_event;
53 1.10.2.2 matt int pmf_debug_idle;
54 1.10.2.2 matt int pmf_debug_transition;
55 1.10.2.2 matt
56 1.10.2.2 matt #define PMF_EVENT_PRINTF(x) if (pmf_debug_event) printf x
57 1.10.2.2 matt #define PMF_IDLE_PRINTF(x) if (pmf_debug_idle) printf x
58 1.10.2.2 matt #define PMF_TRANSITION_PRINTF(x) if (pmf_debug_transition) printf x
59 1.10.2.2 matt #define PMF_TRANSITION_PRINTF2(y,x) if (pmf_debug_transition>y) printf x
60 1.10.2.2 matt #else
61 1.10.2.2 matt #define PMF_EVENT_PRINTF(x) do { } while (0)
62 1.10.2.2 matt #define PMF_IDLE_PRINTF(x) do { } while (0)
63 1.10.2.2 matt #define PMF_TRANSITION_PRINTF(x) do { } while (0)
64 1.10.2.2 matt #define PMF_TRANSITION_PRINTF2(y,x) do { } while (0)
65 1.10.2.2 matt #endif
66 1.10.2.2 matt
67 1.10.2.2 matt /* #define PMF_DEBUG */
68 1.10.2.2 matt
69 1.10.2.2 matt MALLOC_DEFINE(M_PMF, "pmf", "device pmf messaging memory");
70 1.10.2.2 matt
71 1.10.2.2 matt static prop_dictionary_t pmf_platform = NULL;
72 1.10.2.2 matt static struct workqueue *pmf_event_workqueue;
73 1.10.2.2 matt
74 1.10.2.2 matt typedef struct pmf_event_handler {
75 1.10.2.2 matt TAILQ_ENTRY(pmf_event_handler) pmf_link;
76 1.10.2.2 matt pmf_generic_event_t pmf_event;
77 1.10.2.2 matt void (*pmf_handler)(device_t);
78 1.10.2.2 matt device_t pmf_device;
79 1.10.2.2 matt bool pmf_global;
80 1.10.2.2 matt } pmf_event_handler_t;
81 1.10.2.2 matt
82 1.10.2.2 matt static TAILQ_HEAD(, pmf_event_handler) pmf_all_events =
83 1.10.2.2 matt TAILQ_HEAD_INITIALIZER(pmf_all_events);
84 1.10.2.2 matt
85 1.10.2.2 matt typedef struct pmf_event_workitem {
86 1.10.2.2 matt struct work pew_work;
87 1.10.2.2 matt pmf_generic_event_t pew_event;
88 1.10.2.2 matt device_t pew_device;
89 1.10.2.2 matt } pmf_event_workitem_t;
90 1.10.2.2 matt
91 1.10.2.2 matt static void
92 1.10.2.2 matt pmf_event_worker(struct work *wk, void *dummy)
93 1.10.2.2 matt {
94 1.10.2.2 matt pmf_event_workitem_t *pew;
95 1.10.2.2 matt pmf_event_handler_t *event;
96 1.10.2.2 matt
97 1.10.2.2 matt pew = (void *)wk;
98 1.10.2.2 matt KASSERT(wk == &pew->pew_work);
99 1.10.2.2 matt KASSERT(pew != NULL);
100 1.10.2.2 matt
101 1.10.2.2 matt TAILQ_FOREACH(event, &pmf_all_events, pmf_link) {
102 1.10.2.2 matt if (event->pmf_event != pew->pew_event)
103 1.10.2.2 matt continue;
104 1.10.2.2 matt if (event->pmf_device == pew->pew_device || event->pmf_global)
105 1.10.2.2 matt (*event->pmf_handler)(event->pmf_device);
106 1.10.2.2 matt }
107 1.10.2.2 matt
108 1.10.2.2 matt free(pew, M_TEMP);
109 1.10.2.2 matt
110 1.10.2.2 matt return;
111 1.10.2.2 matt }
112 1.10.2.2 matt
113 1.10.2.2 matt static bool
114 1.10.2.2 matt pmf_check_system_drivers(void)
115 1.10.2.2 matt {
116 1.10.2.2 matt device_t curdev;
117 1.10.2.2 matt bool unsupported_devs;
118 1.10.2.2 matt
119 1.10.2.2 matt unsupported_devs = false;
120 1.10.2.2 matt TAILQ_FOREACH(curdev, &alldevs, dv_list) {
121 1.10.2.2 matt if (device_pmf_is_registered(curdev))
122 1.10.2.2 matt continue;
123 1.10.2.2 matt if (!unsupported_devs)
124 1.10.2.2 matt printf("Devices without power management support:");
125 1.10.2.2 matt printf(" %s", device_xname(curdev));
126 1.10.2.2 matt unsupported_devs = true;
127 1.10.2.2 matt }
128 1.10.2.2 matt if (unsupported_devs) {
129 1.10.2.2 matt printf("\n");
130 1.10.2.2 matt return false;
131 1.10.2.2 matt }
132 1.10.2.2 matt return true;
133 1.10.2.2 matt }
134 1.10.2.2 matt
135 1.10.2.2 matt bool
136 1.10.2.2 matt pmf_system_bus_resume(void)
137 1.10.2.2 matt {
138 1.10.2.2 matt int depth, maxdepth;
139 1.10.2.2 matt bool rv;
140 1.10.2.2 matt device_t curdev;
141 1.10.2.2 matt
142 1.10.2.2 matt maxdepth = 0;
143 1.10.2.2 matt TAILQ_FOREACH(curdev, &alldevs, dv_list) {
144 1.10.2.2 matt if (curdev->dv_depth > maxdepth)
145 1.10.2.2 matt maxdepth = curdev->dv_depth;
146 1.10.2.2 matt }
147 1.10.2.2 matt ++maxdepth;
148 1.10.2.2 matt
149 1.10.2.2 matt aprint_debug("Powering devices:");
150 1.10.2.2 matt /* D0 handlers are run in order */
151 1.10.2.2 matt depth = 0;
152 1.10.2.2 matt rv = true;
153 1.10.2.2 matt for (depth = 0; depth < maxdepth; ++depth) {
154 1.10.2.2 matt TAILQ_FOREACH(curdev, &alldevs, dv_list) {
155 1.10.2.2 matt if (!device_pmf_is_registered(curdev))
156 1.10.2.2 matt continue;
157 1.10.2.2 matt if (device_is_active(curdev) ||
158 1.10.2.2 matt !device_is_enabled(curdev))
159 1.10.2.2 matt continue;
160 1.10.2.2 matt if (curdev->dv_depth != depth)
161 1.10.2.2 matt continue;
162 1.10.2.2 matt
163 1.10.2.2 matt aprint_debug(" %s", device_xname(curdev));
164 1.10.2.2 matt
165 1.10.2.2 matt if (!device_pmf_bus_resume(curdev))
166 1.10.2.2 matt aprint_debug("(failed)");
167 1.10.2.2 matt }
168 1.10.2.2 matt }
169 1.10.2.2 matt aprint_debug("\n");
170 1.10.2.2 matt
171 1.10.2.2 matt return rv;
172 1.10.2.2 matt }
173 1.10.2.2 matt
174 1.10.2.2 matt bool
175 1.10.2.2 matt pmf_system_resume(void)
176 1.10.2.2 matt {
177 1.10.2.2 matt int depth, maxdepth;
178 1.10.2.2 matt bool rv;
179 1.10.2.2 matt device_t curdev, parent;
180 1.10.2.2 matt
181 1.10.2.2 matt if (!pmf_check_system_drivers())
182 1.10.2.2 matt return false;
183 1.10.2.2 matt
184 1.10.2.2 matt maxdepth = 0;
185 1.10.2.2 matt TAILQ_FOREACH(curdev, &alldevs, dv_list) {
186 1.10.2.2 matt if (curdev->dv_depth > maxdepth)
187 1.10.2.2 matt maxdepth = curdev->dv_depth;
188 1.10.2.2 matt }
189 1.10.2.2 matt ++maxdepth;
190 1.10.2.2 matt
191 1.10.2.2 matt aprint_debug("Resuming devices:");
192 1.10.2.2 matt /* D0 handlers are run in order */
193 1.10.2.2 matt depth = 0;
194 1.10.2.2 matt rv = true;
195 1.10.2.2 matt for (depth = 0; depth < maxdepth; ++depth) {
196 1.10.2.2 matt TAILQ_FOREACH(curdev, &alldevs, dv_list) {
197 1.10.2.2 matt if (device_is_active(curdev) ||
198 1.10.2.2 matt !device_is_enabled(curdev))
199 1.10.2.2 matt continue;
200 1.10.2.2 matt if (curdev->dv_depth != depth)
201 1.10.2.2 matt continue;
202 1.10.2.2 matt parent = device_parent(curdev);
203 1.10.2.2 matt if (parent != NULL &&
204 1.10.2.2 matt !device_is_active(parent))
205 1.10.2.2 matt continue;
206 1.10.2.2 matt
207 1.10.2.2 matt aprint_debug(" %s", device_xname(curdev));
208 1.10.2.2 matt
209 1.10.2.2 matt if (!pmf_device_resume(curdev)) {
210 1.10.2.2 matt rv = false;
211 1.10.2.2 matt aprint_debug("(failed)");
212 1.10.2.2 matt }
213 1.10.2.2 matt }
214 1.10.2.2 matt }
215 1.10.2.2 matt aprint_debug(".\n");
216 1.10.2.2 matt
217 1.10.2.2 matt return rv;
218 1.10.2.2 matt }
219 1.10.2.2 matt
220 1.10.2.2 matt bool
221 1.10.2.2 matt pmf_system_suspend(void)
222 1.10.2.2 matt {
223 1.10.2.2 matt int depth, maxdepth;
224 1.10.2.2 matt device_t curdev;
225 1.10.2.2 matt
226 1.10.2.2 matt if (!pmf_check_system_drivers())
227 1.10.2.2 matt return false;
228 1.10.2.2 matt
229 1.10.2.2 matt /*
230 1.10.2.2 matt * Flush buffers only if the shutdown didn't do so
231 1.10.2.2 matt * already and if there was no panic.
232 1.10.2.2 matt */
233 1.10.2.2 matt if (doing_shutdown == 0 && panicstr == NULL) {
234 1.10.2.2 matt printf("Flushing disk caches: ");
235 1.10.2.2 matt sys_sync(NULL, NULL, NULL);
236 1.10.2.2 matt if (buf_syncwait() != 0)
237 1.10.2.2 matt printf("giving up\n");
238 1.10.2.2 matt else
239 1.10.2.2 matt printf("done\n");
240 1.10.2.2 matt }
241 1.10.2.2 matt
242 1.10.2.2 matt aprint_debug("Suspending devices:");
243 1.10.2.2 matt
244 1.10.2.2 matt maxdepth = 0;
245 1.10.2.2 matt TAILQ_FOREACH(curdev, &alldevs, dv_list) {
246 1.10.2.2 matt if (curdev->dv_depth > maxdepth)
247 1.10.2.2 matt maxdepth = curdev->dv_depth;
248 1.10.2.2 matt }
249 1.10.2.2 matt
250 1.10.2.2 matt for (depth = maxdepth; depth >= 0; --depth) {
251 1.10.2.2 matt TAILQ_FOREACH_REVERSE(curdev, &alldevs, devicelist, dv_list) {
252 1.10.2.2 matt if (curdev->dv_depth != depth)
253 1.10.2.2 matt continue;
254 1.10.2.2 matt if (!device_is_active(curdev))
255 1.10.2.2 matt continue;
256 1.10.2.2 matt
257 1.10.2.2 matt aprint_debug(" %s", device_xname(curdev));
258 1.10.2.2 matt
259 1.10.2.2 matt /* XXX joerg check return value and abort suspend */
260 1.10.2.2 matt if (!pmf_device_suspend(curdev))
261 1.10.2.2 matt aprint_debug("(failed)");
262 1.10.2.2 matt }
263 1.10.2.2 matt }
264 1.10.2.2 matt
265 1.10.2.2 matt aprint_debug(".\n");
266 1.10.2.2 matt
267 1.10.2.2 matt return true;
268 1.10.2.2 matt }
269 1.10.2.2 matt
270 1.10.2.2 matt void
271 1.10.2.2 matt pmf_system_shutdown(void)
272 1.10.2.2 matt {
273 1.10.2.2 matt int depth, maxdepth;
274 1.10.2.2 matt device_t curdev;
275 1.10.2.2 matt
276 1.10.2.2 matt aprint_debug("Shutting down devices:");
277 1.10.2.2 matt
278 1.10.2.2 matt maxdepth = 0;
279 1.10.2.2 matt TAILQ_FOREACH(curdev, &alldevs, dv_list) {
280 1.10.2.2 matt if (curdev->dv_depth > maxdepth)
281 1.10.2.2 matt maxdepth = curdev->dv_depth;
282 1.10.2.2 matt }
283 1.10.2.2 matt
284 1.10.2.2 matt for (depth = maxdepth; depth >= 0; --depth) {
285 1.10.2.2 matt TAILQ_FOREACH_REVERSE(curdev, &alldevs, devicelist, dv_list) {
286 1.10.2.2 matt if (curdev->dv_depth != depth)
287 1.10.2.2 matt continue;
288 1.10.2.2 matt if (!device_is_active(curdev))
289 1.10.2.2 matt continue;
290 1.10.2.2 matt
291 1.10.2.2 matt aprint_debug(" %s", device_xname(curdev));
292 1.10.2.2 matt
293 1.10.2.2 matt if (!device_pmf_is_registered(curdev))
294 1.10.2.2 matt continue;
295 1.10.2.2 matt if (!device_pmf_class_suspend(curdev)) {
296 1.10.2.2 matt aprint_debug("(failed)");
297 1.10.2.2 matt continue;
298 1.10.2.2 matt }
299 1.10.2.2 matt if (!device_pmf_driver_suspend(curdev)) {
300 1.10.2.2 matt aprint_debug("(failed)");
301 1.10.2.2 matt continue;
302 1.10.2.2 matt }
303 1.10.2.2 matt }
304 1.10.2.2 matt }
305 1.10.2.2 matt
306 1.10.2.2 matt aprint_debug(".\n");
307 1.10.2.2 matt }
308 1.10.2.2 matt
309 1.10.2.2 matt bool
310 1.10.2.2 matt pmf_set_platform(const char *key, const char *value)
311 1.10.2.2 matt {
312 1.10.2.2 matt if (pmf_platform == NULL)
313 1.10.2.2 matt pmf_platform = prop_dictionary_create();
314 1.10.2.2 matt if (pmf_platform == NULL)
315 1.10.2.2 matt return false;
316 1.10.2.2 matt
317 1.10.2.2 matt return prop_dictionary_set_cstring(pmf_platform, key, value);
318 1.10.2.2 matt }
319 1.10.2.2 matt
320 1.10.2.2 matt const char *
321 1.10.2.2 matt pmf_get_platform(const char *key)
322 1.10.2.2 matt {
323 1.10.2.2 matt const char *value;
324 1.10.2.2 matt
325 1.10.2.2 matt if (pmf_platform == NULL)
326 1.10.2.2 matt return NULL;
327 1.10.2.2 matt
328 1.10.2.2 matt if (!prop_dictionary_get_cstring_nocopy(pmf_platform, key, &value))
329 1.10.2.2 matt return NULL;
330 1.10.2.2 matt
331 1.10.2.2 matt return value;
332 1.10.2.2 matt }
333 1.10.2.2 matt
334 1.10.2.2 matt bool
335 1.10.2.2 matt pmf_device_register(device_t dev,
336 1.10.2.2 matt bool (*suspend)(device_t), bool (*resume)(device_t))
337 1.10.2.2 matt {
338 1.10.2.2 matt device_pmf_driver_register(dev, suspend, resume);
339 1.10.2.2 matt
340 1.10.2.2 matt if (!device_pmf_driver_child_register(dev)) {
341 1.10.2.2 matt device_pmf_driver_deregister(dev);
342 1.10.2.2 matt return false;
343 1.10.2.2 matt }
344 1.10.2.2 matt
345 1.10.2.2 matt return true;
346 1.10.2.2 matt }
347 1.10.2.2 matt
348 1.10.2.2 matt void
349 1.10.2.2 matt pmf_device_deregister(device_t dev)
350 1.10.2.2 matt {
351 1.10.2.2 matt device_pmf_class_deregister(dev);
352 1.10.2.2 matt device_pmf_bus_deregister(dev);
353 1.10.2.2 matt device_pmf_driver_deregister(dev);
354 1.10.2.2 matt }
355 1.10.2.2 matt
356 1.10.2.2 matt bool
357 1.10.2.2 matt pmf_device_suspend(device_t dev)
358 1.10.2.2 matt {
359 1.10.2.2 matt PMF_TRANSITION_PRINTF(("%s: suspend enter\n", device_xname(dev)));
360 1.10.2.2 matt if (!device_pmf_is_registered(dev))
361 1.10.2.2 matt return false;
362 1.10.2.2 matt PMF_TRANSITION_PRINTF2(1, ("%s: class suspend\n", device_xname(dev)));
363 1.10.2.2 matt if (!device_pmf_class_suspend(dev))
364 1.10.2.2 matt return false;
365 1.10.2.2 matt PMF_TRANSITION_PRINTF2(1, ("%s: driver suspend\n", device_xname(dev)));
366 1.10.2.2 matt if (!device_pmf_driver_suspend(dev))
367 1.10.2.2 matt return false;
368 1.10.2.2 matt PMF_TRANSITION_PRINTF2(1, ("%s: bus suspend\n", device_xname(dev)));
369 1.10.2.2 matt if (!device_pmf_bus_suspend(dev))
370 1.10.2.2 matt return false;
371 1.10.2.2 matt PMF_TRANSITION_PRINTF(("%s: suspend exit\n", device_xname(dev)));
372 1.10.2.2 matt return true;
373 1.10.2.2 matt }
374 1.10.2.2 matt
375 1.10.2.2 matt bool
376 1.10.2.2 matt pmf_device_resume(device_t dev)
377 1.10.2.2 matt {
378 1.10.2.2 matt PMF_TRANSITION_PRINTF(("%s: resume enter\n", device_xname(dev)));
379 1.10.2.2 matt if (!device_pmf_is_registered(dev))
380 1.10.2.2 matt return false;
381 1.10.2.2 matt PMF_TRANSITION_PRINTF2(1, ("%s: bus resume\n", device_xname(dev)));
382 1.10.2.2 matt if (!device_pmf_bus_resume(dev))
383 1.10.2.2 matt return false;
384 1.10.2.2 matt PMF_TRANSITION_PRINTF2(1, ("%s: driver resume\n", device_xname(dev)));
385 1.10.2.2 matt if (!device_pmf_driver_resume(dev))
386 1.10.2.2 matt return false;
387 1.10.2.2 matt PMF_TRANSITION_PRINTF2(1, ("%s: class resume\n", device_xname(dev)));
388 1.10.2.2 matt if (!device_pmf_class_resume(dev))
389 1.10.2.2 matt return false;
390 1.10.2.2 matt PMF_TRANSITION_PRINTF(("%s: resume exit\n", device_xname(dev)));
391 1.10.2.2 matt return true;
392 1.10.2.2 matt }
393 1.10.2.2 matt
394 1.10.2.2 matt bool
395 1.10.2.2 matt pmf_device_recursive_suspend(device_t dv)
396 1.10.2.2 matt {
397 1.10.2.2 matt device_t curdev;
398 1.10.2.2 matt
399 1.10.2.2 matt if (!device_is_active(dv))
400 1.10.2.2 matt return true;
401 1.10.2.2 matt
402 1.10.2.2 matt TAILQ_FOREACH(curdev, &alldevs, dv_list) {
403 1.10.2.2 matt if (device_parent(curdev) != dv)
404 1.10.2.2 matt continue;
405 1.10.2.2 matt if (!pmf_device_recursive_suspend(curdev))
406 1.10.2.2 matt return false;
407 1.10.2.2 matt }
408 1.10.2.2 matt
409 1.10.2.2 matt return pmf_device_suspend(dv);
410 1.10.2.2 matt }
411 1.10.2.2 matt
412 1.10.2.2 matt bool
413 1.10.2.2 matt pmf_device_recursive_resume(device_t dv)
414 1.10.2.2 matt {
415 1.10.2.2 matt device_t parent;
416 1.10.2.2 matt
417 1.10.2.2 matt if (device_is_active(dv))
418 1.10.2.2 matt return true;
419 1.10.2.2 matt
420 1.10.2.2 matt parent = device_parent(dv);
421 1.10.2.2 matt if (parent != NULL) {
422 1.10.2.2 matt if (!pmf_device_recursive_resume(parent))
423 1.10.2.2 matt return false;
424 1.10.2.2 matt }
425 1.10.2.2 matt
426 1.10.2.2 matt return pmf_device_resume(dv);
427 1.10.2.2 matt }
428 1.10.2.2 matt
429 1.10.2.2 matt bool
430 1.10.2.2 matt pmf_device_resume_subtree(device_t dv)
431 1.10.2.2 matt {
432 1.10.2.2 matt device_t curdev;
433 1.10.2.2 matt
434 1.10.2.2 matt if (!pmf_device_recursive_resume(dv))
435 1.10.2.2 matt return false;
436 1.10.2.2 matt
437 1.10.2.2 matt TAILQ_FOREACH(curdev, &alldevs, dv_list) {
438 1.10.2.2 matt if (device_parent(curdev) != dv)
439 1.10.2.2 matt continue;
440 1.10.2.2 matt if (!pmf_device_resume_subtree(curdev))
441 1.10.2.2 matt return false;
442 1.10.2.2 matt }
443 1.10.2.2 matt return true;
444 1.10.2.2 matt }
445 1.10.2.2 matt
446 1.10.2.2 matt #include <net/if.h>
447 1.10.2.2 matt
448 1.10.2.2 matt static bool
449 1.10.2.2 matt pmf_class_network_suspend(device_t dev)
450 1.10.2.2 matt {
451 1.10.2.2 matt struct ifnet *ifp = device_pmf_class_private(dev);
452 1.10.2.2 matt int s;
453 1.10.2.2 matt
454 1.10.2.2 matt s = splnet();
455 1.10.2.2 matt (*ifp->if_stop)(ifp, 1);
456 1.10.2.2 matt splx(s);
457 1.10.2.2 matt
458 1.10.2.2 matt return true;
459 1.10.2.2 matt }
460 1.10.2.2 matt
461 1.10.2.2 matt static bool
462 1.10.2.2 matt pmf_class_network_resume(device_t dev)
463 1.10.2.2 matt {
464 1.10.2.2 matt struct ifnet *ifp = device_pmf_class_private(dev);
465 1.10.2.2 matt int s;
466 1.10.2.2 matt
467 1.10.2.2 matt s = splnet();
468 1.10.2.2 matt if (ifp->if_flags & IFF_UP) {
469 1.10.2.2 matt ifp->if_flags &= ~IFF_RUNNING;
470 1.10.2.2 matt (*ifp->if_init)(ifp);
471 1.10.2.2 matt (*ifp->if_start)(ifp);
472 1.10.2.2 matt }
473 1.10.2.2 matt splx(s);
474 1.10.2.2 matt
475 1.10.2.2 matt return true;
476 1.10.2.2 matt }
477 1.10.2.2 matt
478 1.10.2.2 matt void
479 1.10.2.2 matt pmf_class_network_register(device_t dev, struct ifnet *ifp)
480 1.10.2.2 matt {
481 1.10.2.2 matt device_pmf_class_register(dev, ifp, pmf_class_network_suspend,
482 1.10.2.2 matt pmf_class_network_resume, NULL);
483 1.10.2.2 matt }
484 1.10.2.2 matt
485 1.10.2.2 matt bool
486 1.10.2.2 matt pmf_event_inject(device_t dv, pmf_generic_event_t ev)
487 1.10.2.2 matt {
488 1.10.2.2 matt pmf_event_workitem_t *pew;
489 1.10.2.2 matt
490 1.10.2.2 matt pew = malloc(sizeof(pmf_event_workitem_t), M_TEMP, M_NOWAIT);
491 1.10.2.2 matt if (pew == NULL) {
492 1.10.2.2 matt PMF_EVENT_PRINTF(("%s: PMF event %d dropped (no memory)\n",
493 1.10.2.2 matt dv ? device_xname(dv) : "<anonymous>", ev));
494 1.10.2.2 matt return false;
495 1.10.2.2 matt }
496 1.10.2.2 matt
497 1.10.2.2 matt pew->pew_event = ev;
498 1.10.2.2 matt pew->pew_device = dv;
499 1.10.2.2 matt
500 1.10.2.2 matt workqueue_enqueue(pmf_event_workqueue, (void *)pew, NULL);
501 1.10.2.2 matt PMF_EVENT_PRINTF(("%s: PMF event %d injected\n",
502 1.10.2.2 matt dv ? device_xname(dv) : "<anonymous>", ev));
503 1.10.2.2 matt
504 1.10.2.2 matt return true;
505 1.10.2.2 matt }
506 1.10.2.2 matt
507 1.10.2.2 matt bool
508 1.10.2.2 matt pmf_event_register(device_t dv, pmf_generic_event_t ev,
509 1.10.2.2 matt void (*handler)(device_t), bool global)
510 1.10.2.2 matt {
511 1.10.2.2 matt pmf_event_handler_t *event;
512 1.10.2.2 matt
513 1.10.2.2 matt event = malloc(sizeof(*event), M_DEVBUF, M_WAITOK);
514 1.10.2.2 matt event->pmf_event = ev;
515 1.10.2.2 matt event->pmf_handler = handler;
516 1.10.2.2 matt event->pmf_device = dv;
517 1.10.2.2 matt event->pmf_global = global;
518 1.10.2.2 matt TAILQ_INSERT_TAIL(&pmf_all_events, event, pmf_link);
519 1.10.2.2 matt
520 1.10.2.2 matt return true;
521 1.10.2.2 matt }
522 1.10.2.2 matt
523 1.10.2.2 matt void
524 1.10.2.2 matt pmf_event_deregister(device_t dv, pmf_generic_event_t ev,
525 1.10.2.2 matt void (*handler)(device_t), bool global)
526 1.10.2.2 matt {
527 1.10.2.2 matt pmf_event_handler_t *event;
528 1.10.2.2 matt
529 1.10.2.2 matt TAILQ_FOREACH(event, &pmf_all_events, pmf_link) {
530 1.10.2.2 matt if (event->pmf_event != ev)
531 1.10.2.2 matt continue;
532 1.10.2.2 matt if (event->pmf_device != dv)
533 1.10.2.2 matt continue;
534 1.10.2.2 matt if (event->pmf_global != global)
535 1.10.2.2 matt continue;
536 1.10.2.2 matt if (event->pmf_handler != handler)
537 1.10.2.2 matt continue;
538 1.10.2.2 matt TAILQ_REMOVE(&pmf_all_events, event, pmf_link);
539 1.10.2.2 matt free(event, M_WAITOK);
540 1.10.2.2 matt return;
541 1.10.2.2 matt }
542 1.10.2.2 matt }
543 1.10.2.2 matt
544 1.10.2.2 matt struct display_class_softc {
545 1.10.2.2 matt TAILQ_ENTRY(display_class_softc) dc_link;
546 1.10.2.2 matt device_t dc_dev;
547 1.10.2.2 matt };
548 1.10.2.2 matt
549 1.10.2.2 matt static TAILQ_HEAD(, display_class_softc) all_displays;
550 1.10.2.2 matt static callout_t global_idle_counter;
551 1.10.2.2 matt static int idle_timeout = 30;
552 1.10.2.2 matt
553 1.10.2.2 matt static void
554 1.10.2.2 matt input_idle(void *dummy)
555 1.10.2.2 matt {
556 1.10.2.2 matt PMF_IDLE_PRINTF(("Input idle handler called\n"));
557 1.10.2.2 matt pmf_event_inject(NULL, PMFE_DISPLAY_OFF);
558 1.10.2.2 matt }
559 1.10.2.2 matt
560 1.10.2.2 matt static void
561 1.10.2.2 matt input_activity_handler(device_t dv, devactive_t type)
562 1.10.2.2 matt {
563 1.10.2.2 matt if (!TAILQ_EMPTY(&all_displays))
564 1.10.2.2 matt callout_schedule(&global_idle_counter, idle_timeout * hz);
565 1.10.2.2 matt }
566 1.10.2.2 matt
567 1.10.2.2 matt static void
568 1.10.2.2 matt pmf_class_input_deregister(device_t dv)
569 1.10.2.2 matt {
570 1.10.2.2 matt device_active_deregister(dv, input_activity_handler);
571 1.10.2.2 matt }
572 1.10.2.2 matt
573 1.10.2.2 matt bool
574 1.10.2.2 matt pmf_class_input_register(device_t dv)
575 1.10.2.2 matt {
576 1.10.2.2 matt if (!device_active_register(dv, input_activity_handler))
577 1.10.2.2 matt return false;
578 1.10.2.2 matt
579 1.10.2.2 matt device_pmf_class_register(dv, NULL, NULL, NULL,
580 1.10.2.2 matt pmf_class_input_deregister);
581 1.10.2.2 matt
582 1.10.2.2 matt return true;
583 1.10.2.2 matt }
584 1.10.2.2 matt
585 1.10.2.2 matt static void
586 1.10.2.2 matt pmf_class_display_deregister(device_t dv)
587 1.10.2.2 matt {
588 1.10.2.2 matt struct display_class_softc *sc = device_pmf_class_private(dv);
589 1.10.2.2 matt int s;
590 1.10.2.2 matt
591 1.10.2.2 matt s = splsoftclock();
592 1.10.2.2 matt TAILQ_REMOVE(&all_displays, sc, dc_link);
593 1.10.2.2 matt if (TAILQ_EMPTY(&all_displays))
594 1.10.2.2 matt callout_stop(&global_idle_counter);
595 1.10.2.2 matt splx(s);
596 1.10.2.2 matt
597 1.10.2.2 matt free(sc, M_DEVBUF);
598 1.10.2.2 matt }
599 1.10.2.2 matt
600 1.10.2.2 matt bool
601 1.10.2.2 matt pmf_class_display_register(device_t dv)
602 1.10.2.2 matt {
603 1.10.2.2 matt struct display_class_softc *sc;
604 1.10.2.2 matt int s;
605 1.10.2.2 matt
606 1.10.2.2 matt sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK);
607 1.10.2.2 matt
608 1.10.2.2 matt s = splsoftclock();
609 1.10.2.2 matt if (TAILQ_EMPTY(&all_displays))
610 1.10.2.2 matt callout_schedule(&global_idle_counter, idle_timeout * hz);
611 1.10.2.2 matt
612 1.10.2.2 matt TAILQ_INSERT_HEAD(&all_displays, sc, dc_link);
613 1.10.2.2 matt splx(s);
614 1.10.2.2 matt
615 1.10.2.2 matt device_pmf_class_register(dv, sc, NULL, NULL,
616 1.10.2.2 matt pmf_class_display_deregister);
617 1.10.2.2 matt
618 1.10.2.2 matt return true;
619 1.10.2.2 matt }
620 1.10.2.2 matt
621 1.10.2.2 matt void
622 1.10.2.2 matt pmf_init(void)
623 1.10.2.2 matt {
624 1.10.2.2 matt int err;
625 1.10.2.2 matt
626 1.10.2.2 matt KASSERT(pmf_event_workqueue == NULL);
627 1.10.2.2 matt err = workqueue_create(&pmf_event_workqueue, "pmfevent",
628 1.10.2.2 matt pmf_event_worker, NULL, PRI_NONE, IPL_VM, 0);
629 1.10.2.2 matt if (err)
630 1.10.2.2 matt panic("couldn't create pmfevent workqueue");
631 1.10.2.2 matt
632 1.10.2.2 matt callout_init(&global_idle_counter, 0);
633 1.10.2.2 matt callout_setfunc(&global_idle_counter, input_idle, NULL);
634 1.10.2.2 matt }
635