The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_pmf.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* $NetBSD: kern_pmf.c,v 1.20 2008/06/17 16:17:21 tsutsui Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   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.
   15  *
   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.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __KERNEL_RCSID(0, "$NetBSD: kern_pmf.c,v 1.20 2008/06/17 16:17:21 tsutsui Exp $");
   31 
   32 #include <sys/types.h>
   33 #include <sys/param.h>
   34 #include <sys/malloc.h>
   35 #include <sys/buf.h>
   36 #include <sys/callout.h>
   37 #include <sys/kernel.h>
   38 #include <sys/device.h>
   39 #include <sys/pmf.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>
   47 #include <sys/proc.h>
   48 #include <sys/reboot.h> /* for RB_NOSYNC */
   49 #include <sys/sched.h>
   50 
   51 /* XXX ugly special case, but for now the only client */
   52 #include "wsdisplay.h"
   53 #if NWSDISPLAY > 0
   54 #include <dev/wscons/wsdisplayvar.h>
   55 #endif
   56 
   57 #ifdef PMF_DEBUG
   58 int pmf_debug_event;
   59 int pmf_debug_idle;
   60 int pmf_debug_transition;
   61 
   62 #define PMF_EVENT_PRINTF(x)             if (pmf_debug_event) printf x
   63 #define PMF_IDLE_PRINTF(x)              if (pmf_debug_idle) printf x
   64 #define PMF_TRANSITION_PRINTF(x)        if (pmf_debug_transition) printf x
   65 #define PMF_TRANSITION_PRINTF2(y,x)     if (pmf_debug_transition>y) printf x
   66 #else
   67 #define PMF_EVENT_PRINTF(x)             do { } while (0)
   68 #define PMF_IDLE_PRINTF(x)              do { } while (0)
   69 #define PMF_TRANSITION_PRINTF(x)        do { } while (0)
   70 #define PMF_TRANSITION_PRINTF2(y,x)     do { } while (0)
   71 #endif
   72 
   73 /* #define PMF_DEBUG */
   74 
   75 MALLOC_DEFINE(M_PMF, "pmf", "device pmf messaging memory");
   76 
   77 static prop_dictionary_t pmf_platform = NULL;
   78 static struct workqueue *pmf_event_workqueue;
   79 
   80 typedef struct pmf_event_handler {
   81         TAILQ_ENTRY(pmf_event_handler) pmf_link;
   82         pmf_generic_event_t pmf_event;
   83         void (*pmf_handler)(device_t);
   84         device_t pmf_device;
   85         bool pmf_global;
   86 } pmf_event_handler_t;
   87 
   88 static TAILQ_HEAD(, pmf_event_handler) pmf_all_events =
   89     TAILQ_HEAD_INITIALIZER(pmf_all_events);
   90 
   91 typedef struct pmf_event_workitem {
   92         struct work             pew_work;
   93         pmf_generic_event_t     pew_event;
   94         device_t                pew_device;
   95 } pmf_event_workitem_t;
   96 
   97 struct shutdown_state {
   98         bool initialized;
   99         deviter_t di;
  100 };
  101 
  102 static device_t shutdown_first(struct shutdown_state *);
  103 static device_t shutdown_next(struct shutdown_state *);
  104 
  105 static bool pmf_device_resume_locked(device_t PMF_FN_PROTO);
  106 static bool pmf_device_suspend_locked(device_t PMF_FN_PROTO);
  107 
  108 static void
  109 pmf_event_worker(struct work *wk, void *dummy)
  110 {
  111         pmf_event_workitem_t *pew;
  112         pmf_event_handler_t *event;
  113 
  114         pew = (void *)wk;
  115         KASSERT(wk == &pew->pew_work);
  116         KASSERT(pew != NULL);
  117         
  118         TAILQ_FOREACH(event, &pmf_all_events, pmf_link) {
  119                 if (event->pmf_event != pew->pew_event)
  120                         continue;
  121                 if (event->pmf_device == pew->pew_device || event->pmf_global)
  122                         (*event->pmf_handler)(event->pmf_device);
  123         }
  124 
  125         free(pew, M_TEMP);
  126 }
  127 
  128 static bool
  129 pmf_check_system_drivers(void)
  130 {
  131         device_t curdev;
  132         bool unsupported_devs;
  133         deviter_t di;
  134 
  135         unsupported_devs = false;
  136         for (curdev = deviter_first(&di, 0); curdev != NULL;
  137              curdev = deviter_next(&di)) {
  138                 if (device_pmf_is_registered(curdev))
  139                         continue;
  140                 if (!unsupported_devs)
  141                         printf("Devices without power management support:");
  142                 printf(" %s", device_xname(curdev));
  143                 unsupported_devs = true;
  144         }
  145         deviter_release(&di);
  146         if (unsupported_devs) {
  147                 printf("\n");
  148                 return false;
  149         }
  150         return true;
  151 }
  152 
  153 bool
  154 pmf_system_bus_resume(PMF_FN_ARGS1)
  155 {
  156         bool rv;
  157         device_t curdev;
  158         deviter_t di;
  159 
  160         aprint_debug("Powering devices:");
  161         /* D0 handlers are run in order */
  162         rv = true;
  163         for (curdev = deviter_first(&di, DEVITER_F_ROOT_FIRST); curdev != NULL;
  164              curdev = deviter_next(&di)) {
  165                 if (!device_pmf_is_registered(curdev))
  166                         continue;
  167                 if (device_is_active(curdev) ||
  168                     !device_is_enabled(curdev))
  169                         continue;
  170 
  171                 aprint_debug(" %s", device_xname(curdev));
  172 
  173                 if (!device_pmf_bus_resume(curdev PMF_FN_CALL)) {
  174                         rv = false;
  175                         aprint_debug("(failed)");
  176                 }
  177         }
  178         deviter_release(&di);
  179         aprint_debug("\n");
  180 
  181         return rv;
  182 }
  183 
  184 bool
  185 pmf_system_resume(PMF_FN_ARGS1)
  186 {
  187         bool rv;
  188         device_t curdev, parent;
  189         deviter_t di;
  190 
  191         if (!pmf_check_system_drivers())
  192                 return false;
  193 
  194         aprint_debug("Resuming devices:");
  195         /* D0 handlers are run in order */
  196         rv = true;
  197         for (curdev = deviter_first(&di, DEVITER_F_ROOT_FIRST); curdev != NULL;
  198              curdev = deviter_next(&di)) {
  199                 if (device_is_active(curdev) ||
  200                     !device_is_enabled(curdev))
  201                         continue;
  202                 parent = device_parent(curdev);
  203                 if (parent != NULL &&
  204                     !device_is_active(parent))
  205                         continue;
  206 
  207                 aprint_debug(" %s", device_xname(curdev));
  208 
  209                 if (!pmf_device_resume(curdev PMF_FN_CALL)) {
  210                         rv = false;
  211                         aprint_debug("(failed)");
  212                 }
  213         }
  214         deviter_release(&di);
  215         aprint_debug(".\n");
  216 
  217         KERNEL_UNLOCK_ONE(0);
  218 #if NWSDISPLAY > 0
  219         if (rv)
  220                 wsdisplay_handlex(1);
  221 #endif
  222         return rv;
  223 }
  224 
  225 bool
  226 pmf_system_suspend(PMF_FN_ARGS1)
  227 {
  228         device_t curdev;
  229         deviter_t di;
  230 
  231         if (!pmf_check_system_drivers())
  232                 return false;
  233 #if NWSDISPLAY > 0
  234         if (wsdisplay_handlex(0))
  235                 return false;
  236 #endif
  237         KERNEL_LOCK(1, 0);
  238 
  239         /*
  240          * Flush buffers only if the shutdown didn't do so
  241          * already and if there was no panic.
  242          */
  243         if (doing_shutdown == 0 && panicstr == NULL) {
  244                 printf("Flushing disk caches: ");
  245                 sys_sync(NULL, NULL, NULL);
  246                 if (buf_syncwait() != 0)
  247                         printf("giving up\n");
  248                 else
  249                         printf("done\n");
  250         }
  251 
  252         aprint_debug("Suspending devices:");
  253 
  254         for (curdev = deviter_first(&di, DEVITER_F_LEAVES_FIRST);
  255              curdev != NULL;
  256              curdev = deviter_next(&di)) {
  257                 if (!device_is_active(curdev))
  258                         continue;
  259 
  260                 aprint_debug(" %s", device_xname(curdev));
  261 
  262                 /* XXX joerg check return value and abort suspend */
  263                 if (!pmf_device_suspend(curdev PMF_FN_CALL))
  264                         aprint_debug("(failed)");
  265         }
  266         deviter_release(&di);
  267 
  268         aprint_debug(".\n");
  269 
  270         return true;
  271 }
  272 
  273 static device_t
  274 shutdown_first(struct shutdown_state *s)
  275 {
  276         if (!s->initialized) {
  277                 deviter_init(&s->di, DEVITER_F_SHUTDOWN|DEVITER_F_LEAVES_FIRST);
  278                 s->initialized = true;
  279         }
  280         return shutdown_next(s);
  281 }
  282 
  283 static device_t
  284 shutdown_next(struct shutdown_state *s)
  285 {
  286         device_t dv;
  287 
  288         while ((dv = deviter_next(&s->di)) != NULL && !device_is_active(dv))
  289                 ;
  290 
  291         return dv;
  292 }
  293 
  294 void
  295 pmf_system_shutdown(int how)
  296 {
  297         static struct shutdown_state s;
  298         device_t curdev;
  299 
  300         aprint_debug("Shutting down devices:");
  301 
  302         for (curdev = shutdown_first(&s); curdev != NULL;
  303              curdev = shutdown_next(&s)) {
  304                 aprint_debug(" attempting %s shutdown",
  305                     device_xname(curdev));
  306                 if (!device_pmf_is_registered(curdev))
  307                         aprint_debug("(skipped)");
  308 #if 0 /* needed? */
  309                 else if (!device_pmf_class_shutdown(curdev, how))
  310                         aprint_debug("(failed)");
  311 #endif
  312                 else if (!device_pmf_driver_shutdown(curdev, how))
  313                         aprint_debug("(failed)");
  314                 else if (!device_pmf_bus_shutdown(curdev, how))
  315                         aprint_debug("(failed)");
  316         }
  317 
  318         aprint_debug(".\n");
  319 }
  320 
  321 bool
  322 pmf_set_platform(const char *key, const char *value)
  323 {
  324         if (pmf_platform == NULL)
  325                 pmf_platform = prop_dictionary_create();
  326         if (pmf_platform == NULL)
  327                 return false;
  328 
  329         return prop_dictionary_set_cstring(pmf_platform, key, value);
  330 }
  331 
  332 const char *
  333 pmf_get_platform(const char *key)
  334 {
  335         const char *value;
  336 
  337         if (pmf_platform == NULL)
  338                 return NULL;
  339 
  340         if (!prop_dictionary_get_cstring_nocopy(pmf_platform, key, &value))
  341                 return NULL;
  342 
  343         return value;
  344 }
  345 
  346 bool
  347 pmf_device_register1(device_t dev,
  348     bool (*suspend)(device_t PMF_FN_PROTO),
  349     bool (*resume)(device_t PMF_FN_PROTO),
  350     bool (*shutdown)(device_t, int))
  351 {
  352         if (!device_pmf_driver_register(dev, suspend, resume, shutdown))
  353                 return false;
  354 
  355         if (!device_pmf_driver_child_register(dev)) {
  356                 device_pmf_driver_deregister(dev);
  357                 return false;
  358         }
  359 
  360         return true;
  361 }
  362 
  363 void
  364 pmf_device_deregister(device_t dev)
  365 {
  366         device_pmf_class_deregister(dev);
  367         device_pmf_bus_deregister(dev);
  368         device_pmf_driver_deregister(dev);
  369 }
  370 
  371 bool
  372 pmf_device_suspend_self(device_t dev)
  373 {
  374         return pmf_device_suspend(dev, PMF_F_SELF);
  375 }
  376 
  377 bool
  378 pmf_device_suspend(device_t dev PMF_FN_ARGS)
  379 {
  380         bool rc;
  381 
  382         PMF_TRANSITION_PRINTF(("%s: suspend enter\n", device_xname(dev)));
  383         if (!device_pmf_is_registered(dev))
  384                 return false;
  385 
  386         if (!device_pmf_lock(dev PMF_FN_CALL))
  387                 return false;
  388 
  389         rc = pmf_device_suspend_locked(dev PMF_FN_CALL);
  390 
  391         device_pmf_unlock(dev PMF_FN_CALL);
  392 
  393         PMF_TRANSITION_PRINTF(("%s: suspend exit\n", device_xname(dev)));
  394         return rc;
  395 }
  396 
  397 static bool
  398 pmf_device_suspend_locked(device_t dev PMF_FN_ARGS)
  399 {
  400         PMF_TRANSITION_PRINTF2(1, ("%s: self suspend\n", device_xname(dev)));
  401         device_pmf_self_suspend(dev, flags);
  402         PMF_TRANSITION_PRINTF2(1, ("%s: class suspend\n", device_xname(dev)));
  403         if (!device_pmf_class_suspend(dev PMF_FN_CALL))
  404                 return false;
  405         PMF_TRANSITION_PRINTF2(1, ("%s: driver suspend\n", device_xname(dev)));
  406         if (!device_pmf_driver_suspend(dev PMF_FN_CALL))
  407                 return false;
  408         PMF_TRANSITION_PRINTF2(1, ("%s: bus suspend\n", device_xname(dev)));
  409         if (!device_pmf_bus_suspend(dev PMF_FN_CALL))
  410                 return false;
  411 
  412         return true;
  413 }
  414 
  415 bool
  416 pmf_device_resume_self(device_t dev)
  417 {
  418         return pmf_device_resume(dev, PMF_F_SELF);
  419 }
  420 
  421 bool
  422 pmf_device_resume(device_t dev PMF_FN_ARGS)
  423 {
  424         bool rc;
  425 
  426         PMF_TRANSITION_PRINTF(("%s: resume enter\n", device_xname(dev)));
  427         if (!device_pmf_is_registered(dev))
  428                 return false;
  429 
  430         if (!device_pmf_lock(dev PMF_FN_CALL))
  431                 return false;
  432 
  433         rc = pmf_device_resume_locked(dev PMF_FN_CALL);
  434 
  435         device_pmf_unlock(dev PMF_FN_CALL);
  436 
  437         PMF_TRANSITION_PRINTF(("%s: resume exit\n", device_xname(dev)));
  438         return rc;
  439 }
  440 
  441 static bool
  442 pmf_device_resume_locked(device_t dev PMF_FN_ARGS)
  443 {
  444         PMF_TRANSITION_PRINTF2(1, ("%s: bus resume\n", device_xname(dev)));
  445         if (!device_pmf_bus_resume(dev PMF_FN_CALL))
  446                 return false;
  447         PMF_TRANSITION_PRINTF2(1, ("%s: driver resume\n", device_xname(dev)));
  448         if (!device_pmf_driver_resume(dev PMF_FN_CALL))
  449                 return false;
  450         PMF_TRANSITION_PRINTF2(1, ("%s: class resume\n", device_xname(dev)));
  451         if (!device_pmf_class_resume(dev PMF_FN_CALL))
  452                 return false;
  453         PMF_TRANSITION_PRINTF2(1, ("%s: self resume\n", device_xname(dev)));
  454         device_pmf_self_resume(dev, flags);
  455 
  456         return true;
  457 }
  458 
  459 bool
  460 pmf_device_recursive_suspend(device_t dv PMF_FN_ARGS)
  461 {
  462         bool rv = true;
  463         device_t curdev;
  464         deviter_t di;
  465 
  466         if (!device_is_active(dv))
  467                 return true;
  468 
  469         for (curdev = deviter_first(&di, 0); curdev != NULL;
  470              curdev = deviter_next(&di)) {
  471                 if (device_parent(curdev) != dv)
  472                         continue;
  473                 if (!pmf_device_recursive_suspend(curdev PMF_FN_CALL)) {
  474                         rv = false;
  475                         break;
  476                 }
  477         }
  478         deviter_release(&di);
  479 
  480         return rv && pmf_device_suspend(dv PMF_FN_CALL);
  481 }
  482 
  483 bool
  484 pmf_device_recursive_resume(device_t dv PMF_FN_ARGS)
  485 {
  486         device_t parent;
  487 
  488         if (device_is_active(dv))
  489                 return true;
  490 
  491         parent = device_parent(dv);
  492         if (parent != NULL) {
  493                 if (!pmf_device_recursive_resume(parent PMF_FN_CALL))
  494                         return false;
  495         }
  496 
  497         return pmf_device_resume(dv PMF_FN_CALL);
  498 }
  499 
  500 bool
  501 pmf_device_resume_subtree(device_t dv PMF_FN_ARGS)
  502 {
  503         bool rv = true;
  504         device_t curdev;
  505         deviter_t di;
  506 
  507         if (!pmf_device_recursive_resume(dv PMF_FN_CALL))
  508                 return false;
  509 
  510         for (curdev = deviter_first(&di, 0); curdev != NULL;
  511              curdev = deviter_next(&di)) {
  512                 if (device_parent(curdev) != dv)
  513                         continue;
  514                 if (!pmf_device_resume_subtree(curdev PMF_FN_CALL)) {
  515                         rv = false;
  516                         break;
  517                 }
  518         }
  519         deviter_release(&di);
  520         return rv;
  521 }
  522 
  523 #include <net/if.h>
  524 
  525 static bool
  526 pmf_class_network_suspend(device_t dev PMF_FN_ARGS)
  527 {
  528         struct ifnet *ifp = device_pmf_class_private(dev);
  529         int s;
  530 
  531         s = splnet();
  532         (*ifp->if_stop)(ifp, 0);
  533         splx(s);
  534 
  535         return true;
  536 }
  537 
  538 static bool
  539 pmf_class_network_resume(device_t dev PMF_FN_ARGS)
  540 {
  541         struct ifnet *ifp = device_pmf_class_private(dev);
  542         int s;
  543 
  544         if ((flags & PMF_F_SELF) != 0)
  545                 return true;
  546 
  547         s = splnet();
  548         if (ifp->if_flags & IFF_UP) {
  549                 ifp->if_flags &= ~IFF_RUNNING;
  550                 if ((*ifp->if_init)(ifp) != 0)
  551                         aprint_normal_ifnet(ifp, "resume failed\n");
  552                 (*ifp->if_start)(ifp);
  553         }
  554         splx(s);
  555 
  556         return true;
  557 }
  558 
  559 void
  560 pmf_class_network_register(device_t dev, struct ifnet *ifp)
  561 {
  562         device_pmf_class_register(dev, ifp, pmf_class_network_suspend,
  563             pmf_class_network_resume, NULL);
  564 }
  565 
  566 bool
  567 pmf_event_inject(device_t dv, pmf_generic_event_t ev)
  568 {
  569         pmf_event_workitem_t *pew;
  570 
  571         pew = malloc(sizeof(pmf_event_workitem_t), M_TEMP, M_NOWAIT);
  572         if (pew == NULL) {
  573                 PMF_EVENT_PRINTF(("%s: PMF event %d dropped (no memory)\n",
  574                     dv ? device_xname(dv) : "<anonymous>", ev));
  575                 return false;
  576         }
  577 
  578         pew->pew_event = ev;
  579         pew->pew_device = dv;
  580 
  581         workqueue_enqueue(pmf_event_workqueue, (void *)pew, NULL);
  582         PMF_EVENT_PRINTF(("%s: PMF event %d injected\n",
  583             dv ? device_xname(dv) : "<anonymous>", ev));
  584 
  585         return true;
  586 }
  587 
  588 bool
  589 pmf_event_register(device_t dv, pmf_generic_event_t ev,
  590     void (*handler)(device_t), bool global)
  591 {
  592         pmf_event_handler_t *event; 
  593         
  594         event = malloc(sizeof(*event), M_DEVBUF, M_WAITOK);
  595         event->pmf_event = ev;
  596         event->pmf_handler = handler;
  597         event->pmf_device = dv;
  598         event->pmf_global = global;
  599         TAILQ_INSERT_TAIL(&pmf_all_events, event, pmf_link);
  600 
  601         return true;
  602 }
  603 
  604 void
  605 pmf_event_deregister(device_t dv, pmf_generic_event_t ev,
  606     void (*handler)(device_t), bool global)
  607 {
  608         pmf_event_handler_t *event;
  609 
  610         TAILQ_FOREACH(event, &pmf_all_events, pmf_link) {
  611                 if (event->pmf_event != ev)
  612                         continue;
  613                 if (event->pmf_device != dv)
  614                         continue;
  615                 if (event->pmf_global != global)
  616                         continue;
  617                 if (event->pmf_handler != handler)
  618                         continue;
  619                 TAILQ_REMOVE(&pmf_all_events, event, pmf_link);
  620                 free(event, M_DEVBUF);
  621                 return;
  622         }
  623 }
  624 
  625 struct display_class_softc {
  626         TAILQ_ENTRY(display_class_softc) dc_link;
  627         device_t dc_dev;
  628 };
  629 
  630 static TAILQ_HEAD(, display_class_softc) all_displays;
  631 static callout_t global_idle_counter;
  632 static int idle_timeout = 30;
  633 
  634 static void
  635 input_idle(void *dummy)
  636 {
  637         PMF_IDLE_PRINTF(("Input idle handler called\n"));
  638         pmf_event_inject(NULL, PMFE_DISPLAY_OFF);
  639 }
  640 
  641 static void
  642 input_activity_handler(device_t dv, devactive_t type)
  643 {
  644         if (!TAILQ_EMPTY(&all_displays))
  645                 callout_schedule(&global_idle_counter, idle_timeout * hz);
  646 }
  647 
  648 static void
  649 pmf_class_input_deregister(device_t dv)
  650 {
  651         device_active_deregister(dv, input_activity_handler);
  652 }
  653 
  654 bool
  655 pmf_class_input_register(device_t dv)
  656 {
  657         if (!device_active_register(dv, input_activity_handler))
  658                 return false;
  659         
  660         device_pmf_class_register(dv, NULL, NULL, NULL,
  661             pmf_class_input_deregister);
  662 
  663         return true;
  664 }
  665 
  666 static void
  667 pmf_class_display_deregister(device_t dv)
  668 {
  669         struct display_class_softc *sc = device_pmf_class_private(dv);
  670         int s;
  671 
  672         s = splsoftclock();
  673         TAILQ_REMOVE(&all_displays, sc, dc_link);
  674         if (TAILQ_EMPTY(&all_displays))
  675                 callout_stop(&global_idle_counter);
  676         splx(s);
  677 
  678         free(sc, M_DEVBUF);
  679 }
  680 
  681 bool
  682 pmf_class_display_register(device_t dv)
  683 {
  684         struct display_class_softc *sc;
  685         int s;
  686 
  687         sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK);
  688 
  689         s = splsoftclock();
  690         if (TAILQ_EMPTY(&all_displays))
  691                 callout_schedule(&global_idle_counter, idle_timeout * hz);
  692 
  693         TAILQ_INSERT_HEAD(&all_displays, sc, dc_link);
  694         splx(s);
  695 
  696         device_pmf_class_register(dv, sc, NULL, NULL,
  697             pmf_class_display_deregister);
  698 
  699         return true;
  700 }
  701 
  702 void
  703 pmf_init(void)
  704 {
  705         int err;
  706 
  707         KASSERT(pmf_event_workqueue == NULL);
  708         err = workqueue_create(&pmf_event_workqueue, "pmfevent",
  709             pmf_event_worker, NULL, PRI_NONE, IPL_VM, 0);
  710         if (err)
  711                 panic("couldn't create pmfevent workqueue");
  712 
  713         callout_init(&global_idle_counter, 0);
  714         callout_setfunc(&global_idle_counter, input_idle, NULL);
  715 }

Cache object: 04d2b820e5e9549458fa5fc8e6ad2f30


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.