1 /* $NetBSD: kern_pmf.c,v 1.30 2009/10/27 02:55:07 rmind Exp $ */
4 * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: kern_pmf.c,v 1.30 2009/10/27 02:55:07 rmind Exp $");
32 #include <sys/types.h>
33 #include <sys/param.h>
36 #include <sys/callout.h>
37 #include <sys/kernel.h>
38 #include <sys/device.h>
40 #include <sys/queue.h>
41 #include <sys/sched.h>
42 #include <sys/syscallargs.h> /* for sys_sync */
43 #include <sys/workqueue.h>
44 #include <prop/proplib.h>
45 #include <sys/condvar.h>
46 #include <sys/mutex.h>
48 #include <sys/reboot.h> /* for RB_NOSYNC */
49 #include <sys/sched.h>
51 /* XXX ugly special case, but for now the only client */
52 #include "wsdisplay.h"
54 #include <dev/wscons/wsdisplayvar.h>
63 int pmf_debug_suspend
;
64 int pmf_debug_suspensor
;
66 int pmf_debug_transition
;
68 #define PMF_SUSPENSOR_PRINTF(x) if (pmf_debug_suspensor) printf x
69 #define PMF_SUSPEND_PRINTF(x) if (pmf_debug_suspend) printf x
70 #define PMF_EVENT_PRINTF(x) if (pmf_debug_event) printf x
71 #define PMF_IDLE_PRINTF(x) if (pmf_debug_idle) printf x
72 #define PMF_TRANSITION_PRINTF(x) if (pmf_debug_transition) printf x
73 #define PMF_TRANSITION_PRINTF2(y,x) if (pmf_debug_transition>y) printf x
75 #define PMF_SUSPENSOR_PRINTF(x) do { } while (0)
76 #define PMF_SUSPEND_PRINTF(x) do { } while (0)
77 #define PMF_EVENT_PRINTF(x) do { } while (0)
78 #define PMF_IDLE_PRINTF(x) do { } while (0)
79 #define PMF_TRANSITION_PRINTF(x) do { } while (0)
80 #define PMF_TRANSITION_PRINTF2(y,x) do { } while (0)
83 /* #define PMF_DEBUG */
85 MALLOC_DEFINE(M_PMF
, "pmf", "device pmf messaging memory");
87 static prop_dictionary_t pmf_platform
= NULL
;
88 static struct workqueue
*pmf_event_workqueue
;
89 static struct workqueue
*pmf_suspend_workqueue
;
91 typedef struct pmf_event_handler
{
92 TAILQ_ENTRY(pmf_event_handler
) pmf_link
;
93 pmf_generic_event_t pmf_event
;
94 void (*pmf_handler
)(device_t
);
97 } pmf_event_handler_t
;
99 static TAILQ_HEAD(, pmf_event_handler
) pmf_all_events
=
100 TAILQ_HEAD_INITIALIZER(pmf_all_events
);
102 typedef struct pmf_event_workitem
{
103 struct work pew_work
;
104 pmf_generic_event_t pew_event
;
106 } pmf_event_workitem_t
;
108 typedef struct pmf_suspend_workitem
{
109 struct work psw_work
;
111 struct pmf_qual psw_qual
;
112 } pmf_suspend_workitem_t
;
114 static struct pool pew_pl
;
116 static pmf_event_workitem_t
*pmf_event_workitem_get(void);
117 static void pmf_event_workitem_put(pmf_event_workitem_t
*);
119 bool pmf_device_resume_locked(device_t
, pmf_qual_t
);
120 bool pmf_device_suspend_locked(device_t
, pmf_qual_t
);
121 static bool device_pmf_any_suspensor(device_t
, devact_level_t
);
124 complete_suspension(device_t dev
, device_suspensor_t
*susp
, pmf_qual_t pqp
)
128 device_suspensor_t ds
;
130 ds
= pmf_qual_suspension(pqp
);
131 KASSERT(ds
->ds_delegator
!= NULL
);
134 pq
.pq_suspensor
= ds
->ds_delegator
;
136 for (i
= 0; i
< DEVICE_SUSPENSORS_MAX
; i
++) {
139 if (!pmf_device_suspend(dev
, &pq
))
146 pmf_suspend_worker(struct work
*wk
, void *dummy
)
148 pmf_suspend_workitem_t
*psw
;
153 KASSERT(wk
== &psw
->psw_work
);
154 KASSERT(psw
!= NULL
);
156 for (dev
= deviter_first(&di
, 0); dev
!= NULL
;
157 dev
= deviter_next(&di
)) {
158 if (dev
== psw
->psw_dev
&& device_pmf_lock(dev
))
161 deviter_release(&di
);
166 switch (pmf_qual_depth(&psw
->psw_qual
)) {
167 case DEVACT_LEVEL_FULL
:
168 if (!complete_suspension(dev
, dev
->dv_class_suspensors
,
172 case DEVACT_LEVEL_DRIVER
:
173 if (!complete_suspension(dev
, dev
->dv_driver_suspensors
,
177 case DEVACT_LEVEL_BUS
:
178 if (!complete_suspension(dev
, dev
->dv_bus_suspensors
,
182 device_pmf_unlock(dev
);
183 kmem_free(psw
, sizeof(*psw
));
187 pmf_event_worker(struct work
*wk
, void *dummy
)
189 pmf_event_workitem_t
*pew
;
190 pmf_event_handler_t
*event
;
193 KASSERT(wk
== &pew
->pew_work
);
194 KASSERT(pew
!= NULL
);
196 TAILQ_FOREACH(event
, &pmf_all_events
, pmf_link
) {
197 if (event
->pmf_event
!= pew
->pew_event
)
199 if (event
->pmf_device
== pew
->pew_device
|| event
->pmf_global
)
200 (*event
->pmf_handler
)(event
->pmf_device
);
203 pmf_event_workitem_put(pew
);
207 pmf_check_system_drivers(void)
210 bool unsupported_devs
;
213 unsupported_devs
= false;
214 for (curdev
= deviter_first(&di
, 0); curdev
!= NULL
;
215 curdev
= deviter_next(&di
)) {
216 if (device_pmf_is_registered(curdev
))
218 if (!unsupported_devs
)
219 printf("Devices without power management support:");
220 printf(" %s", device_xname(curdev
));
221 unsupported_devs
= true;
223 deviter_release(&di
);
224 if (unsupported_devs
) {
232 pmf_system_bus_resume(pmf_qual_t qual
)
238 aprint_debug("Powering devices:");
239 /* D0 handlers are run in order */
241 for (curdev
= deviter_first(&di
, DEVITER_F_ROOT_FIRST
); curdev
!= NULL
;
242 curdev
= deviter_next(&di
)) {
243 if (!device_pmf_is_registered(curdev
))
245 if (device_is_active(curdev
) ||
246 !device_is_enabled(curdev
))
249 aprint_debug(" %s", device_xname(curdev
));
251 if (!device_pmf_bus_resume(curdev
, qual
)) {
253 aprint_debug("(failed)");
256 deviter_release(&di
);
263 pmf_system_resume(pmf_qual_t qual
)
266 device_t curdev
, parent
;
269 if (!pmf_check_system_drivers())
272 aprint_debug("Resuming devices:");
273 /* D0 handlers are run in order */
275 for (curdev
= deviter_first(&di
, DEVITER_F_ROOT_FIRST
); curdev
!= NULL
;
276 curdev
= deviter_next(&di
)) {
277 if (device_is_active(curdev
) ||
278 !device_is_enabled(curdev
))
280 parent
= device_parent(curdev
);
281 if (parent
!= NULL
&&
282 !device_is_active(parent
))
285 aprint_debug(" %s", device_xname(curdev
));
287 if (!pmf_device_resume(curdev
, qual
)) {
289 aprint_debug("(failed)");
292 deviter_release(&di
);
295 KERNEL_UNLOCK_ONE(0);
298 wsdisplay_handlex(1);
304 pmf_system_suspend(pmf_qual_t qual
)
309 if (!pmf_check_system_drivers())
312 if (wsdisplay_handlex(0))
315 KERNEL_LOCK(1, NULL
);
318 * Flush buffers only if the shutdown didn't do so
319 * already and if there was no panic.
321 if (doing_shutdown
== 0 && panicstr
== NULL
) {
322 printf("Flushing disk caches: ");
323 sys_sync(NULL
, NULL
, NULL
);
324 if (buf_syncwait() != 0)
325 printf("giving up\n");
330 aprint_debug("Suspending devices:");
332 for (curdev
= deviter_first(&di
, DEVITER_F_LEAVES_FIRST
);
334 curdev
= deviter_next(&di
)) {
335 if (!device_is_active(curdev
))
338 aprint_debug(" %s", device_xname(curdev
));
340 /* XXX joerg check return value and abort suspend */
341 if (!pmf_device_suspend(curdev
, qual
))
342 aprint_debug("(failed)");
344 deviter_release(&di
);
352 shutdown_all(int how
)
354 static struct shutdown_state s
;
356 bool progress
= false;
358 for (curdev
= shutdown_first(&s
); curdev
!= NULL
;
359 curdev
= shutdown_next(&s
)) {
360 aprint_debug(" shutting down %s, ", device_xname(curdev
));
361 if (!device_pmf_is_registered(curdev
))
362 aprint_debug("skipped.");
364 else if (!device_pmf_class_shutdown(curdev
, how
))
365 aprint_debug("failed.");
367 else if (!device_pmf_driver_shutdown(curdev
, how
))
368 aprint_debug("failed.");
369 else if (!device_pmf_bus_shutdown(curdev
, how
))
370 aprint_debug("failed.");
373 aprint_debug("success.");
380 pmf_system_shutdown(int how
)
382 aprint_debug("Shutting down devices:");
387 pmf_set_platform(const char *key
, const char *value
)
389 if (pmf_platform
== NULL
)
390 pmf_platform
= prop_dictionary_create();
391 if (pmf_platform
== NULL
)
394 return prop_dictionary_set_cstring(pmf_platform
, key
, value
);
398 pmf_get_platform(const char *key
)
402 if (pmf_platform
== NULL
)
405 if (!prop_dictionary_get_cstring_nocopy(pmf_platform
, key
, &value
))
412 pmf_device_register1(device_t dev
,
413 bool (*suspend
)(device_t
, pmf_qual_t
),
414 bool (*resume
)(device_t
, pmf_qual_t
),
415 bool (*shutdown
)(device_t
, int))
417 if (!device_pmf_driver_register(dev
, suspend
, resume
, shutdown
))
420 if (!device_pmf_driver_child_register(dev
)) {
421 device_pmf_driver_deregister(dev
);
429 pmf_device_deregister(device_t dev
)
431 device_pmf_class_deregister(dev
);
432 device_pmf_bus_deregister(dev
);
433 device_pmf_driver_deregister(dev
);
436 static const struct device_suspensor _device_suspensor_drvctl
= {
438 , .ds_name
= "drvctl"
441 static const struct device_suspensor _device_suspensor_self
= {
447 static const struct device_suspensor _device_suspensor_self_delegate
= {
448 .ds_delegator
= &_device_suspensor_self
449 , .ds_name
= "self delegate"
453 static const struct device_suspensor _device_suspensor_system
= {
455 , .ds_name
= "system"
458 const struct device_suspensor
459 * const device_suspensor_self
= &_device_suspensor_self
,
461 * const device_suspensor_self_delegate
= &_device_suspensor_self_delegate
,
463 * const device_suspensor_system
= &_device_suspensor_system
,
464 * const device_suspensor_drvctl
= &_device_suspensor_drvctl
;
466 static const struct pmf_qual _pmf_qual_system
= {
467 .pq_actlvl
= DEVACT_LEVEL_FULL
468 , .pq_suspensor
= &_device_suspensor_system
471 static const struct pmf_qual _pmf_qual_drvctl
= {
472 .pq_actlvl
= DEVACT_LEVEL_FULL
473 , .pq_suspensor
= &_device_suspensor_drvctl
476 static const struct pmf_qual _pmf_qual_self
= {
477 .pq_actlvl
= DEVACT_LEVEL_DRIVER
478 , .pq_suspensor
= &_device_suspensor_self
481 const struct pmf_qual
482 * const PMF_Q_DRVCTL
= &_pmf_qual_drvctl
,
483 * const PMF_Q_NONE
= &_pmf_qual_system
,
484 * const PMF_Q_SELF
= &_pmf_qual_self
;
487 device_suspensor_delegates_to(device_suspensor_t ds
,
488 device_suspensor_t delegate
)
490 device_suspensor_t iter
;
492 for (iter
= delegate
->ds_delegator
; iter
!= NULL
;
493 iter
= iter
->ds_delegator
) {
501 add_suspensor(device_t dev
, const char *kind
, device_suspensor_t
*susp
,
502 device_suspensor_t ds
)
506 for (i
= 0; i
< DEVICE_SUSPENSORS_MAX
; i
++) {
510 PMF_SUSPENSOR_PRINTF((
511 "%s: %s-suspended by %s (delegator %s) already\n",
512 device_xname(dev
), kind
,
514 (susp
[i
]->ds_delegator
!= NULL
) ?
515 susp
[i
]->ds_delegator
->ds_name
: "<none>"));
518 if (device_suspensor_delegates_to(ds
, susp
[i
])) {
519 PMF_SUSPENSOR_PRINTF((
520 "%s: %s assumes %s-suspension by %s "
522 device_xname(dev
), ds
->ds_name
, kind
,
524 (susp
[i
]->ds_delegator
!= NULL
) ?
525 susp
[i
]->ds_delegator
->ds_name
: "<none>"));
530 for (i
= 0; i
< DEVICE_SUSPENSORS_MAX
; i
++) {
531 if (susp
[i
] == NULL
) {
533 PMF_SUSPENSOR_PRINTF((
534 "%s: newly %s-suspended by %s (delegator %s)\n",
535 device_xname(dev
), kind
,
537 (susp
[i
]->ds_delegator
!= NULL
) ?
538 susp
[i
]->ds_delegator
->ds_name
: "<none>"));
546 device_pmf_add_suspensor(device_t dev
, pmf_qual_t pq
)
548 device_suspensor_t ds
;
552 ds
= pmf_qual_suspension(pq
);
556 if (!add_suspensor(dev
, "class", dev
->dv_class_suspensors
, ds
))
558 if (!add_suspensor(dev
, "driver", dev
->dv_driver_suspensors
, ds
))
560 if (!add_suspensor(dev
, "bus", dev
->dv_bus_suspensors
, ds
))
567 device_pmf_has_suspension(device_t dev
, device_suspensor_t ds
)
571 for (i
= 0; i
< DEVICE_SUSPENSORS_MAX
; i
++) {
572 if (dev
->dv_suspensions
[i
] == ds
)
574 if (device_suspensor_delegates_to(dev
->dv_suspensions
[i
], ds
))
582 any_suspensor(device_t dev
, const char *kind
, device_suspensor_t
*susp
)
585 bool suspended
= false;
587 for (i
= 0; i
< DEVICE_SUSPENSORS_MAX
; i
++) {
588 if (susp
[i
] != NULL
) {
589 PMF_SUSPENSOR_PRINTF(("%s: %s is suspended by %s "
591 device_xname(dev
), kind
,
593 (susp
[i
]->ds_delegator
!= NULL
) ?
594 susp
[i
]->ds_delegator
->ds_name
: "<none>"));
602 device_pmf_any_suspensor(device_t dev
, devact_level_t depth
)
605 case DEVACT_LEVEL_FULL
:
606 if (any_suspensor(dev
, "class", dev
->dv_class_suspensors
))
609 case DEVACT_LEVEL_DRIVER
:
610 if (any_suspensor(dev
, "driver", dev
->dv_driver_suspensors
))
613 case DEVACT_LEVEL_BUS
:
614 if (any_suspensor(dev
, "bus", dev
->dv_bus_suspensors
))
621 remove_suspensor(device_t dev
, const char *kind
, device_suspensor_t
*susp
,
622 device_suspensor_t ds
)
626 for (i
= 0; i
< DEVICE_SUSPENSORS_MAX
; i
++) {
630 device_suspensor_delegates_to(ds
, susp
[i
])) {
631 PMF_SUSPENSOR_PRINTF(("%s: %s suspension %s "
632 "(delegator %s) removed by %s\n",
633 device_xname(dev
), kind
,
635 (susp
[i
]->ds_delegator
!= NULL
)
636 ? susp
[i
]->ds_delegator
->ds_name
647 device_pmf_remove_suspensor(device_t dev
, pmf_qual_t pq
)
649 device_suspensor_t ds
;
653 ds
= pmf_qual_suspension(pq
);
657 if (!remove_suspensor(dev
, "class", dev
->dv_class_suspensors
, ds
))
659 if (!remove_suspensor(dev
, "driver", dev
->dv_driver_suspensors
, ds
))
661 if (!remove_suspensor(dev
, "bus", dev
->dv_bus_suspensors
, ds
))
668 pmf_self_suspensor_init(device_t dev
, struct device_suspensor
*ds
,
671 ds
->ds_delegator
= device_suspensor_self
;
672 snprintf(ds
->ds_name
, sizeof(ds
->ds_name
), "%s-self",
674 pq
->pq_actlvl
= DEVACT_LEVEL_DRIVER
;
675 pq
->pq_suspensor
= ds
;
679 pmf_device_suspend(device_t dev
, pmf_qual_t qual
)
683 PMF_TRANSITION_PRINTF(("%s: suspend enter\n", device_xname(dev
)));
684 if (!device_pmf_is_registered(dev
))
687 if (!device_pmf_lock(dev
))
690 rc
= pmf_device_suspend_locked(dev
, qual
);
692 device_pmf_unlock(dev
);
694 PMF_TRANSITION_PRINTF(("%s: suspend exit\n", device_xname(dev
)));
699 pmf_device_suspend_locked(device_t dev
, pmf_qual_t qual
)
701 if (!device_pmf_add_suspensor(dev
, qual
))
704 PMF_TRANSITION_PRINTF2(1, ("%s: class suspend\n", device_xname(dev
)));
705 if (!device_pmf_class_suspend(dev
, qual
))
708 PMF_TRANSITION_PRINTF2(1, ("%s: driver suspend\n", device_xname(dev
)));
709 if (!device_pmf_driver_suspend(dev
, qual
))
712 PMF_TRANSITION_PRINTF2(1, ("%s: bus suspend\n", device_xname(dev
)));
713 if (!device_pmf_bus_suspend(dev
, qual
))
720 pmf_device_resume(device_t dev
, pmf_qual_t qual
)
724 PMF_TRANSITION_PRINTF(("%s: resume enter\n", device_xname(dev
)));
725 if (!device_pmf_is_registered(dev
))
728 if (!device_pmf_lock(dev
))
731 rc
= pmf_device_resume_locked(dev
, qual
);
733 device_pmf_unlock(dev
);
735 PMF_TRANSITION_PRINTF(("%s: resume exit\n", device_xname(dev
)));
740 pmf_device_resume_locked(device_t dev
, pmf_qual_t qual
)
742 device_pmf_remove_suspensor(dev
, qual
);
744 if (device_pmf_any_suspensor(dev
, DEVACT_LEVEL_FULL
))
747 PMF_TRANSITION_PRINTF2(1, ("%s: bus resume\n", device_xname(dev
)));
748 if (!device_pmf_bus_resume(dev
, qual
))
751 PMF_TRANSITION_PRINTF2(1, ("%s: driver resume\n", device_xname(dev
)));
752 if (!device_pmf_driver_resume(dev
, qual
))
755 PMF_TRANSITION_PRINTF2(1, ("%s: class resume\n", device_xname(dev
)));
756 if (!device_pmf_class_resume(dev
, qual
))
763 pmf_device_recursive_suspend(device_t dv
, pmf_qual_t qual
)
770 pmf_qual_recursive_copy(&pq
, qual
);
772 for (curdev
= deviter_first(&di
, 0); curdev
!= NULL
;
773 curdev
= deviter_next(&di
)) {
774 if (device_parent(curdev
) != dv
)
776 if (!pmf_device_recursive_suspend(curdev
, &pq
)) {
781 deviter_release(&di
);
783 return rv
&& pmf_device_suspend(dv
, qual
);
787 pmf_qual_recursive_copy(struct pmf_qual
*dst
, pmf_qual_t src
)
790 dst
->pq_actlvl
= DEVACT_LEVEL_FULL
;
794 pmf_device_recursive_resume(device_t dv
, pmf_qual_t qual
)
799 if (device_is_active(dv
))
802 pmf_qual_recursive_copy(&pq
, qual
);
804 parent
= device_parent(dv
);
805 if (parent
!= NULL
) {
806 if (!pmf_device_recursive_resume(parent
, &pq
))
810 return pmf_device_resume(dv
, qual
);
814 pmf_device_descendants_release(device_t dv
, pmf_qual_t qual
)
820 for (curdev
= deviter_first(&di
, 0); curdev
!= NULL
;
821 curdev
= deviter_next(&di
)) {
822 if (device_parent(curdev
) != dv
)
824 device_pmf_remove_suspensor(curdev
, qual
);
825 if (!pmf_device_descendants_release(curdev
, qual
)) {
830 deviter_release(&di
);
835 pmf_device_descendants_resume(device_t dv
, pmf_qual_t qual
)
841 KASSERT(pmf_qual_descend_ok(qual
));
843 for (curdev
= deviter_first(&di
, 0); curdev
!= NULL
;
844 curdev
= deviter_next(&di
)) {
845 if (device_parent(curdev
) != dv
)
847 if (!pmf_device_resume(curdev
, qual
) ||
848 !pmf_device_descendants_resume(curdev
, qual
)) {
853 deviter_release(&di
);
858 pmf_device_subtree_release(device_t dv
, pmf_qual_t qual
)
862 device_pmf_remove_suspensor(dv
, qual
);
864 return pmf_device_descendants_release(dv
, &pq
);
868 pmf_device_subtree_resume(device_t dv
, pmf_qual_t qual
)
872 if (!pmf_device_subtree_release(dv
, qual
))
875 if (!pmf_device_recursive_resume(dv
, qual
))
878 pmf_qual_recursive_copy(&pq
, qual
);
880 return pmf_device_descendants_resume(dv
, &pq
);
886 pmf_class_network_suspend(device_t dev
, pmf_qual_t qual
)
888 struct ifnet
*ifp
= device_pmf_class_private(dev
);
892 (*ifp
->if_stop
)(ifp
, 0);
899 pmf_class_network_resume(device_t dev
, pmf_qual_t qual
)
901 struct ifnet
*ifp
= device_pmf_class_private(dev
);
905 if (ifp
->if_flags
& IFF_UP
) {
906 ifp
->if_flags
&= ~IFF_RUNNING
;
907 if ((*ifp
->if_init
)(ifp
) != 0)
908 aprint_normal_ifnet(ifp
, "resume failed\n");
909 (*ifp
->if_start
)(ifp
);
917 pmf_class_network_register(device_t dev
, struct ifnet
*ifp
)
919 device_pmf_class_register(dev
, ifp
, pmf_class_network_suspend
,
920 pmf_class_network_resume
, NULL
);
924 pmf_event_inject(device_t dv
, pmf_generic_event_t ev
)
926 pmf_event_workitem_t
*pew
;
928 pew
= pmf_event_workitem_get();
930 PMF_EVENT_PRINTF(("%s: PMF event %d dropped (no memory)\n",
931 dv
? device_xname(dv
) : "<anonymous>", ev
));
936 pew
->pew_device
= dv
;
938 workqueue_enqueue(pmf_event_workqueue
, &pew
->pew_work
, NULL
);
939 PMF_EVENT_PRINTF(("%s: PMF event %d injected\n",
940 dv
? device_xname(dv
) : "<anonymous>", ev
));
946 pmf_event_register(device_t dv
, pmf_generic_event_t ev
,
947 void (*handler
)(device_t
), bool global
)
949 pmf_event_handler_t
*event
;
951 event
= kmem_alloc(sizeof(*event
), KM_SLEEP
);
952 event
->pmf_event
= ev
;
953 event
->pmf_handler
= handler
;
954 event
->pmf_device
= dv
;
955 event
->pmf_global
= global
;
956 TAILQ_INSERT_TAIL(&pmf_all_events
, event
, pmf_link
);
962 pmf_event_deregister(device_t dv
, pmf_generic_event_t ev
,
963 void (*handler
)(device_t
), bool global
)
965 pmf_event_handler_t
*event
;
967 TAILQ_FOREACH(event
, &pmf_all_events
, pmf_link
) {
968 if (event
->pmf_event
!= ev
)
970 if (event
->pmf_device
!= dv
)
972 if (event
->pmf_global
!= global
)
974 if (event
->pmf_handler
!= handler
)
976 TAILQ_REMOVE(&pmf_all_events
, event
, pmf_link
);
977 kmem_free(event
, sizeof(*event
));
982 struct display_class_softc
{
983 TAILQ_ENTRY(display_class_softc
) dc_link
;
987 static TAILQ_HEAD(, display_class_softc
) all_displays
;
988 static callout_t global_idle_counter
;
989 static int idle_timeout
= 30;
992 input_idle(void *dummy
)
994 PMF_IDLE_PRINTF(("Input idle handler called\n"));
995 pmf_event_inject(NULL
, PMFE_DISPLAY_OFF
);
999 input_activity_handler(device_t dv
, devactive_t type
)
1001 if (!TAILQ_EMPTY(&all_displays
))
1002 callout_schedule(&global_idle_counter
, idle_timeout
* hz
);
1006 pmf_class_input_deregister(device_t dv
)
1008 device_active_deregister(dv
, input_activity_handler
);
1012 pmf_class_input_register(device_t dv
)
1014 if (!device_active_register(dv
, input_activity_handler
))
1017 device_pmf_class_register(dv
, NULL
, NULL
, NULL
,
1018 pmf_class_input_deregister
);
1024 pmf_class_display_deregister(device_t dv
)
1026 struct display_class_softc
*sc
= device_pmf_class_private(dv
);
1030 TAILQ_REMOVE(&all_displays
, sc
, dc_link
);
1031 if (TAILQ_EMPTY(&all_displays
))
1032 callout_stop(&global_idle_counter
);
1035 kmem_free(sc
, sizeof(*sc
));
1039 pmf_class_display_register(device_t dv
)
1041 struct display_class_softc
*sc
;
1044 sc
= kmem_alloc(sizeof(*sc
), KM_SLEEP
);
1047 if (TAILQ_EMPTY(&all_displays
))
1048 callout_schedule(&global_idle_counter
, idle_timeout
* hz
);
1050 TAILQ_INSERT_HEAD(&all_displays
, sc
, dc_link
);
1053 device_pmf_class_register(dv
, sc
, NULL
, NULL
,
1054 pmf_class_display_deregister
);
1060 pmf_event_workitem_put(pmf_event_workitem_t
*pew
)
1063 KASSERT(pew
!= NULL
);
1064 pool_put(&pew_pl
, pew
);
1067 static pmf_event_workitem_t
*
1068 pmf_event_workitem_get(void)
1071 return pool_get(&pew_pl
, PR_NOWAIT
);
1079 pool_init(&pew_pl
, sizeof(pmf_event_workitem_t
), 0, 0, 0,
1080 "pewpl", NULL
, IPL_HIGH
);
1081 pool_setlowat(&pew_pl
, 1);
1082 pool_sethiwat(&pew_pl
, 8);
1084 KASSERT(pmf_event_workqueue
== NULL
);
1085 err
= workqueue_create(&pmf_event_workqueue
, "pmfevent",
1086 pmf_event_worker
, NULL
, PRI_NONE
, IPL_VM
, 0);
1088 panic("couldn't create pmfevent workqueue");
1090 KASSERT(pmf_suspend_workqueue
== NULL
);
1091 err
= workqueue_create(&pmf_suspend_workqueue
, "pmfsuspend",
1092 pmf_suspend_worker
, NULL
, PRI_NONE
, IPL_VM
, 0);
1094 panic("couldn't create pmfsuspend workqueue");
1097 callout_init(&global_idle_counter
, 0);
1098 callout_setfunc(&global_idle_counter
, input_idle
, NULL
);