1 /* $NetBSD: kern_pmf.c,v 1.26 2009/04/17 20:45:09 dyoung 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.26 2009/04/17 20:45:09 dyoung 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, NULL); 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 if (dv == NULL) 292 s->initialized = false; 293 294 return dv; 295 } 296 297 static bool 298 detach_all(int how) 299 { 300 static struct shutdown_state s; 301 device_t curdev; 302 bool progress = false; 303 304 if ((how & RB_NOSYNC) != 0) 305 return false; 306 307 for (curdev = shutdown_first(&s); curdev != NULL; 308 curdev = shutdown_next(&s)) { 309 aprint_debug(" detaching %s, ", device_xname(curdev)); 310 if (config_detach(curdev, DETACH_SHUTDOWN) == 0) { 311 progress = true; 312 aprint_debug("success."); 313 } else 314 aprint_debug("failed."); 315 } 316 return progress; 317 } 318 319 static bool 320 shutdown_all(int how) 321 { 322 static struct shutdown_state s; 323 device_t curdev; 324 bool progress = false; 325 326 for (curdev = shutdown_first(&s); curdev != NULL; 327 curdev = shutdown_next(&s)) { 328 aprint_debug(" shutting down %s, ", device_xname(curdev)); 329 if (!device_pmf_is_registered(curdev)) 330 aprint_debug("skipped."); 331 #if 0 /* needed? */ 332 else if (!device_pmf_class_shutdown(curdev, how)) 333 aprint_debug("failed."); 334 #endif 335 else if (!device_pmf_driver_shutdown(curdev, how)) 336 aprint_debug("failed."); 337 else if (!device_pmf_bus_shutdown(curdev, how)) 338 aprint_debug("failed."); 339 else { 340 progress = true; 341 aprint_debug("success."); 342 } 343 } 344 return progress; 345 } 346 347 void 348 pmf_system_shutdown(int how) 349 { 350 aprint_debug("Shutting down devices:"); 351 suspendsched(); 352 353 while (detach_all(how)) 354 ; 355 356 shutdown_all(how); 357 } 358 359 bool 360 pmf_set_platform(const char *key, const char *value) 361 { 362 if (pmf_platform == NULL) 363 pmf_platform = prop_dictionary_create(); 364 if (pmf_platform == NULL) 365 return false; 366 367 return prop_dictionary_set_cstring(pmf_platform, key, value); 368 } 369 370 const char * 371 pmf_get_platform(const char *key) 372 { 373 const char *value; 374 375 if (pmf_platform == NULL) 376 return NULL; 377 378 if (!prop_dictionary_get_cstring_nocopy(pmf_platform, key, &value)) 379 return NULL; 380 381 return value; 382 } 383 384 bool 385 pmf_device_register1(device_t dev, 386 bool (*suspend)(device_t PMF_FN_PROTO), 387 bool (*resume)(device_t PMF_FN_PROTO), 388 bool (*shutdown)(device_t, int)) 389 { 390 if (!device_pmf_driver_register(dev, suspend, resume, shutdown)) 391 return false; 392 393 if (!device_pmf_driver_child_register(dev)) { 394 device_pmf_driver_deregister(dev); 395 return false; 396 } 397 398 return true; 399 } 400 401 void 402 pmf_device_deregister(device_t dev) 403 { 404 device_pmf_class_deregister(dev); 405 device_pmf_bus_deregister(dev); 406 device_pmf_driver_deregister(dev); 407 } 408 409 bool 410 pmf_device_suspend_self(device_t dev) 411 { 412 return pmf_device_suspend(dev, PMF_F_SELF); 413 } 414 415 bool 416 pmf_device_suspend(device_t dev PMF_FN_ARGS) 417 { 418 bool rc; 419 420 PMF_TRANSITION_PRINTF(("%s: suspend enter\n", device_xname(dev))); 421 if (!device_pmf_is_registered(dev)) 422 return false; 423 424 if (!device_pmf_lock(dev PMF_FN_CALL)) 425 return false; 426 427 rc = pmf_device_suspend_locked(dev PMF_FN_CALL); 428 429 device_pmf_unlock(dev PMF_FN_CALL); 430 431 PMF_TRANSITION_PRINTF(("%s: suspend exit\n", device_xname(dev))); 432 return rc; 433 } 434 435 static bool 436 pmf_device_suspend_locked(device_t dev PMF_FN_ARGS) 437 { 438 PMF_TRANSITION_PRINTF2(1, ("%s: self suspend\n", device_xname(dev))); 439 device_pmf_self_suspend(dev, flags); 440 PMF_TRANSITION_PRINTF2(1, ("%s: class suspend\n", device_xname(dev))); 441 if (!device_pmf_class_suspend(dev PMF_FN_CALL)) 442 return false; 443 PMF_TRANSITION_PRINTF2(1, ("%s: driver suspend\n", device_xname(dev))); 444 if (!device_pmf_driver_suspend(dev PMF_FN_CALL)) 445 return false; 446 PMF_TRANSITION_PRINTF2(1, ("%s: bus suspend\n", device_xname(dev))); 447 if (!device_pmf_bus_suspend(dev PMF_FN_CALL)) 448 return false; 449 450 return true; 451 } 452 453 bool 454 pmf_device_resume_self(device_t dev) 455 { 456 return pmf_device_resume(dev, PMF_F_SELF); 457 } 458 459 bool 460 pmf_device_resume(device_t dev PMF_FN_ARGS) 461 { 462 bool rc; 463 464 PMF_TRANSITION_PRINTF(("%s: resume enter\n", device_xname(dev))); 465 if (!device_pmf_is_registered(dev)) 466 return false; 467 468 if (!device_pmf_lock(dev PMF_FN_CALL)) 469 return false; 470 471 rc = pmf_device_resume_locked(dev PMF_FN_CALL); 472 473 device_pmf_unlock(dev PMF_FN_CALL); 474 475 PMF_TRANSITION_PRINTF(("%s: resume exit\n", device_xname(dev))); 476 return rc; 477 } 478 479 static bool 480 pmf_device_resume_locked(device_t dev PMF_FN_ARGS) 481 { 482 PMF_TRANSITION_PRINTF2(1, ("%s: bus resume\n", device_xname(dev))); 483 if (!device_pmf_bus_resume(dev PMF_FN_CALL)) 484 return false; 485 PMF_TRANSITION_PRINTF2(1, ("%s: driver resume\n", device_xname(dev))); 486 if (!device_pmf_driver_resume(dev PMF_FN_CALL)) 487 return false; 488 PMF_TRANSITION_PRINTF2(1, ("%s: class resume\n", device_xname(dev))); 489 if (!device_pmf_class_resume(dev PMF_FN_CALL)) 490 return false; 491 PMF_TRANSITION_PRINTF2(1, ("%s: self resume\n", device_xname(dev))); 492 device_pmf_self_resume(dev, flags); 493 494 return true; 495 } 496 497 bool 498 pmf_device_recursive_suspend(device_t dv PMF_FN_ARGS) 499 { 500 bool rv = true; 501 device_t curdev; 502 deviter_t di; 503 504 if (!device_is_active(dv)) 505 return true; 506 507 for (curdev = deviter_first(&di, 0); curdev != NULL; 508 curdev = deviter_next(&di)) { 509 if (device_parent(curdev) != dv) 510 continue; 511 if (!pmf_device_recursive_suspend(curdev PMF_FN_CALL)) { 512 rv = false; 513 break; 514 } 515 } 516 deviter_release(&di); 517 518 return rv && pmf_device_suspend(dv PMF_FN_CALL); 519 } 520 521 bool 522 pmf_device_recursive_resume(device_t dv PMF_FN_ARGS) 523 { 524 device_t parent; 525 526 if (device_is_active(dv)) 527 return true; 528 529 parent = device_parent(dv); 530 if (parent != NULL) { 531 if (!pmf_device_recursive_resume(parent PMF_FN_CALL)) 532 return false; 533 } 534 535 return pmf_device_resume(dv PMF_FN_CALL); 536 } 537 538 bool 539 pmf_device_resume_descendants(device_t dv PMF_FN_ARGS) 540 { 541 bool rv = true; 542 device_t curdev; 543 deviter_t di; 544 545 for (curdev = deviter_first(&di, 0); curdev != NULL; 546 curdev = deviter_next(&di)) { 547 if (device_parent(curdev) != dv) 548 continue; 549 if (!pmf_device_resume_subtree(curdev PMF_FN_CALL)) { 550 rv = false; 551 break; 552 } 553 } 554 deviter_release(&di); 555 return rv; 556 } 557 558 bool 559 pmf_device_resume_subtree(device_t dv PMF_FN_ARGS) 560 { 561 if (!pmf_device_recursive_resume(dv PMF_FN_CALL)) 562 return false; 563 564 return pmf_device_resume_descendants(dv PMF_FN_CALL); 565 } 566 567 #include <net/if.h> 568 569 static bool 570 pmf_class_network_suspend(device_t dev PMF_FN_ARGS) 571 { 572 struct ifnet *ifp = device_pmf_class_private(dev); 573 int s; 574 575 s = splnet(); 576 (*ifp->if_stop)(ifp, 0); 577 splx(s); 578 579 return true; 580 } 581 582 static bool 583 pmf_class_network_resume(device_t dev PMF_FN_ARGS) 584 { 585 struct ifnet *ifp = device_pmf_class_private(dev); 586 int s; 587 588 if ((flags & PMF_F_SELF) != 0) 589 return true; 590 591 s = splnet(); 592 if (ifp->if_flags & IFF_UP) { 593 ifp->if_flags &= ~IFF_RUNNING; 594 if ((*ifp->if_init)(ifp) != 0) 595 aprint_normal_ifnet(ifp, "resume failed\n"); 596 (*ifp->if_start)(ifp); 597 } 598 splx(s); 599 600 return true; 601 } 602 603 void 604 pmf_class_network_register(device_t dev, struct ifnet *ifp) 605 { 606 device_pmf_class_register(dev, ifp, pmf_class_network_suspend, 607 pmf_class_network_resume, NULL); 608 } 609 610 bool 611 pmf_event_inject(device_t dv, pmf_generic_event_t ev) 612 { 613 pmf_event_workitem_t *pew; 614 615 pew = malloc(sizeof(pmf_event_workitem_t), M_TEMP, M_NOWAIT); 616 if (pew == NULL) { 617 PMF_EVENT_PRINTF(("%s: PMF event %d dropped (no memory)\n", 618 dv ? device_xname(dv) : "<anonymous>", ev)); 619 return false; 620 } 621 622 pew->pew_event = ev; 623 pew->pew_device = dv; 624 625 workqueue_enqueue(pmf_event_workqueue, (void *)pew, NULL); 626 PMF_EVENT_PRINTF(("%s: PMF event %d injected\n", 627 dv ? device_xname(dv) : "<anonymous>", ev)); 628 629 return true; 630 } 631 632 bool 633 pmf_event_register(device_t dv, pmf_generic_event_t ev, 634 void (*handler)(device_t), bool global) 635 { 636 pmf_event_handler_t *event; 637 638 event = malloc(sizeof(*event), M_DEVBUF, M_WAITOK); 639 event->pmf_event = ev; 640 event->pmf_handler = handler; 641 event->pmf_device = dv; 642 event->pmf_global = global; 643 TAILQ_INSERT_TAIL(&pmf_all_events, event, pmf_link); 644 645 return true; 646 } 647 648 void 649 pmf_event_deregister(device_t dv, pmf_generic_event_t ev, 650 void (*handler)(device_t), bool global) 651 { 652 pmf_event_handler_t *event; 653 654 TAILQ_FOREACH(event, &pmf_all_events, pmf_link) { 655 if (event->pmf_event != ev) 656 continue; 657 if (event->pmf_device != dv) 658 continue; 659 if (event->pmf_global != global) 660 continue; 661 if (event->pmf_handler != handler) 662 continue; 663 TAILQ_REMOVE(&pmf_all_events, event, pmf_link); 664 free(event, M_DEVBUF); 665 return; 666 } 667 } 668 669 struct display_class_softc { 670 TAILQ_ENTRY(display_class_softc) dc_link; 671 device_t dc_dev; 672 }; 673 674 static TAILQ_HEAD(, display_class_softc) all_displays; 675 static callout_t global_idle_counter; 676 static int idle_timeout = 30; 677 678 static void 679 input_idle(void *dummy) 680 { 681 PMF_IDLE_PRINTF(("Input idle handler called\n")); 682 pmf_event_inject(NULL, PMFE_DISPLAY_OFF); 683 } 684 685 static void 686 input_activity_handler(device_t dv, devactive_t type) 687 { 688 if (!TAILQ_EMPTY(&all_displays)) 689 callout_schedule(&global_idle_counter, idle_timeout * hz); 690 } 691 692 static void 693 pmf_class_input_deregister(device_t dv) 694 { 695 device_active_deregister(dv, input_activity_handler); 696 } 697 698 bool 699 pmf_class_input_register(device_t dv) 700 { 701 if (!device_active_register(dv, input_activity_handler)) 702 return false; 703 704 device_pmf_class_register(dv, NULL, NULL, NULL, 705 pmf_class_input_deregister); 706 707 return true; 708 } 709 710 static void 711 pmf_class_display_deregister(device_t dv) 712 { 713 struct display_class_softc *sc = device_pmf_class_private(dv); 714 int s; 715 716 s = splsoftclock(); 717 TAILQ_REMOVE(&all_displays, sc, dc_link); 718 if (TAILQ_EMPTY(&all_displays)) 719 callout_stop(&global_idle_counter); 720 splx(s); 721 722 free(sc, M_DEVBUF); 723 } 724 725 bool 726 pmf_class_display_register(device_t dv) 727 { 728 struct display_class_softc *sc; 729 int s; 730 731 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK); 732 733 s = splsoftclock(); 734 if (TAILQ_EMPTY(&all_displays)) 735 callout_schedule(&global_idle_counter, idle_timeout * hz); 736 737 TAILQ_INSERT_HEAD(&all_displays, sc, dc_link); 738 splx(s); 739 740 device_pmf_class_register(dv, sc, NULL, NULL, 741 pmf_class_display_deregister); 742 743 return true; 744 } 745 746 void 747 pmf_init(void) 748 { 749 int err; 750 751 KASSERT(pmf_event_workqueue == NULL); 752 err = workqueue_create(&pmf_event_workqueue, "pmfevent", 753 pmf_event_worker, NULL, PRI_NONE, IPL_VM, 0); 754 if (err) 755 panic("couldn't create pmfevent workqueue"); 756 757 callout_init(&global_idle_counter, 0); 758 callout_setfunc(&global_idle_counter, input_idle, NULL); 759 } 760