1 /* $NetBSD: sysmon_power.c,v 1.53 2015/04/13 16:33:25 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2007 Juan Romero Pardines. 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 /* 29 * Copyright (c) 2003 Wasabi Systems, Inc. 30 * All rights reserved. 31 * 32 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 33 * 34 * Redistribution and use in source and binary forms, with or without 35 * modification, are permitted provided that the following conditions 36 * are met: 37 * 1. Redistributions of source code must retain the above copyright 38 * notice, this list of conditions and the following disclaimer. 39 * 2. Redistributions in binary form must reproduce the above copyright 40 * notice, this list of conditions and the following disclaimer in the 41 * documentation and/or other materials provided with the distribution. 42 * 3. All advertising materials mentioning features or use of this software 43 * must display the following acknowledgement: 44 * This product includes software developed for the NetBSD Project by 45 * Wasabi Systems, Inc. 46 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 47 * or promote products derived from this software without specific prior 48 * written permission. 49 * 50 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 52 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 53 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 54 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 55 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 56 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 57 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 58 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 59 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 60 * POSSIBILITY OF SUCH DAMAGE. 61 */ 62 63 /* 64 * Power management framework for sysmon. 65 * 66 * We defer to a power management daemon running in userspace, since 67 * power management is largely a policy issue. This merely provides 68 * for power management event notification to that daemon. 69 */ 70 71 #include <sys/cdefs.h> 72 __KERNEL_RCSID(0, "$NetBSD: sysmon_power.c,v 1.53 2015/04/13 16:33:25 riastradh Exp $"); 73 74 #include "opt_compat_netbsd.h" 75 #include <sys/param.h> 76 #include <sys/reboot.h> 77 #include <sys/systm.h> 78 #include <sys/poll.h> 79 #include <sys/select.h> 80 #include <sys/vnode.h> 81 #include <sys/condvar.h> 82 #include <sys/mutex.h> 83 #include <sys/kmem.h> 84 #include <sys/proc.h> 85 #include <sys/device.h> 86 #include <sys/rndsource.h> 87 88 #include <dev/sysmon/sysmonvar.h> 89 #include <prop/proplib.h> 90 91 /* 92 * Singly linked list for dictionaries to be stored/sent. 93 */ 94 struct power_event_dictionary { 95 SIMPLEQ_ENTRY(power_event_dictionary) pev_dict_head; 96 prop_dictionary_t dict; 97 int flags; 98 }; 99 100 struct power_event_description { 101 int type; 102 const char *desc; 103 }; 104 105 /* 106 * Available events for power switches. 107 */ 108 static const struct power_event_description pswitch_event_desc[] = { 109 { PSWITCH_EVENT_PRESSED, "pressed" }, 110 { PSWITCH_EVENT_RELEASED, "released" }, 111 { -1, NULL } 112 }; 113 114 /* 115 * Available script names for power switches. 116 */ 117 static const struct power_event_description pswitch_type_desc[] = { 118 { PSWITCH_TYPE_POWER, "power_button" }, 119 { PSWITCH_TYPE_SLEEP, "sleep_button" }, 120 { PSWITCH_TYPE_LID, "lid_switch" }, 121 { PSWITCH_TYPE_RESET, "reset_button" }, 122 { PSWITCH_TYPE_ACADAPTER, "acadapter" }, 123 { PSWITCH_TYPE_HOTKEY, "hotkey_button" }, 124 { PSWITCH_TYPE_RADIO, "radio_button" }, 125 { -1, NULL } 126 }; 127 128 /* 129 * Available events for envsys(4). 130 */ 131 static const struct power_event_description penvsys_event_desc[] = { 132 { PENVSYS_EVENT_NORMAL, "normal" }, 133 { PENVSYS_EVENT_CRITICAL, "critical" }, 134 { PENVSYS_EVENT_CRITOVER, "critical-over" }, 135 { PENVSYS_EVENT_CRITUNDER, "critical-under" }, 136 { PENVSYS_EVENT_WARNOVER, "warning-over" }, 137 { PENVSYS_EVENT_WARNUNDER, "warning-under" }, 138 { PENVSYS_EVENT_BATT_CRIT, "critical-capacity" }, 139 { PENVSYS_EVENT_BATT_WARN, "warning-capacity" }, 140 { PENVSYS_EVENT_BATT_HIGH, "high-capacity" }, 141 { PENVSYS_EVENT_BATT_MAX, "maximum-capacity" }, 142 { PENVSYS_EVENT_STATE_CHANGED, "state-changed" }, 143 { PENVSYS_EVENT_LOW_POWER, "low-power" }, 144 { -1, NULL } 145 }; 146 147 /* 148 * Available script names for envsys(4). 149 */ 150 static const struct power_event_description penvsys_type_desc[] = { 151 { PENVSYS_TYPE_BATTERY, "sensor_battery" }, 152 { PENVSYS_TYPE_DRIVE, "sensor_drive" }, 153 { PENVSYS_TYPE_FAN, "sensor_fan" }, 154 { PENVSYS_TYPE_INDICATOR, "sensor_indicator" }, 155 { PENVSYS_TYPE_POWER, "sensor_power" }, 156 { PENVSYS_TYPE_RESISTANCE, "sensor_resistance" }, 157 { PENVSYS_TYPE_TEMP, "sensor_temperature" }, 158 { PENVSYS_TYPE_VOLTAGE, "sensor_voltage" }, 159 { -1, NULL } 160 }; 161 162 #define SYSMON_MAX_POWER_EVENTS 32 163 #define SYSMON_POWER_DICTIONARY_BUSY 0x01 164 #define SYSMON_POWER_DICTIONARY_READY 0x02 165 166 static power_event_t sysmon_power_event_queue[SYSMON_MAX_POWER_EVENTS]; 167 static int sysmon_power_event_queue_head; 168 static int sysmon_power_event_queue_tail; 169 static int sysmon_power_event_queue_count; 170 171 static krndsource_t sysmon_rndsource; 172 173 static SIMPLEQ_HEAD(, power_event_dictionary) pev_dict_list = 174 SIMPLEQ_HEAD_INITIALIZER(pev_dict_list); 175 176 static struct selinfo sysmon_power_event_queue_selinfo; 177 static struct lwp *sysmon_power_daemon; 178 179 static kmutex_t sysmon_power_event_queue_mtx; 180 static kcondvar_t sysmon_power_event_queue_cv; 181 182 static char sysmon_power_type[32]; 183 184 static int sysmon_power_make_dictionary(prop_dictionary_t, void *, int, int); 185 static int sysmon_power_daemon_task(struct power_event_dictionary *, 186 void *, int); 187 static void sysmon_power_destroy_dictionary(struct power_event_dictionary *); 188 189 #define SYSMON_NEXT_EVENT(x) (((x) + 1) % SYSMON_MAX_POWER_EVENTS) 190 191 /* 192 * sysmon_power_init: 193 * 194 * Initializes the mutexes and condition variables in the 195 * boot process via init_main.c. 196 */ 197 void 198 sysmon_power_init(void) 199 { 200 mutex_init(&sysmon_power_event_queue_mtx, MUTEX_DEFAULT, IPL_NONE); 201 cv_init(&sysmon_power_event_queue_cv, "smpower"); 202 selinit(&sysmon_power_event_queue_selinfo); 203 204 rnd_attach_source(&sysmon_rndsource, "system-power", 205 RND_TYPE_POWER, RND_FLAG_DEFAULT); 206 207 } 208 209 /* 210 * sysmon_queue_power_event: 211 * 212 * Enqueue a power event for the power management daemon. Returns 213 * non-zero if we were able to enqueue a power event. 214 */ 215 static int 216 sysmon_queue_power_event(power_event_t *pev) 217 { 218 KASSERT(mutex_owned(&sysmon_power_event_queue_mtx)); 219 220 if (sysmon_power_event_queue_count == SYSMON_MAX_POWER_EVENTS) 221 return 0; 222 223 sysmon_power_event_queue[sysmon_power_event_queue_head] = *pev; 224 sysmon_power_event_queue_head = 225 SYSMON_NEXT_EVENT(sysmon_power_event_queue_head); 226 sysmon_power_event_queue_count++; 227 228 return 1; 229 } 230 231 /* 232 * sysmon_get_power_event: 233 * 234 * Get a power event from the queue. Returns non-zero if there 235 * is an event available. 236 */ 237 static int 238 sysmon_get_power_event(power_event_t *pev) 239 { 240 KASSERT(mutex_owned(&sysmon_power_event_queue_mtx)); 241 242 if (sysmon_power_event_queue_count == 0) 243 return 0; 244 245 *pev = sysmon_power_event_queue[sysmon_power_event_queue_tail]; 246 sysmon_power_event_queue_tail = 247 SYSMON_NEXT_EVENT(sysmon_power_event_queue_tail); 248 sysmon_power_event_queue_count--; 249 250 return 1; 251 } 252 253 /* 254 * sysmon_power_event_queue_flush: 255 * 256 * Flush the event queue, and reset all state. 257 */ 258 static void 259 sysmon_power_event_queue_flush(void) 260 { 261 KASSERT(mutex_owned(&sysmon_power_event_queue_mtx)); 262 263 sysmon_power_event_queue_head = 0; 264 sysmon_power_event_queue_tail = 0; 265 sysmon_power_event_queue_count = 0; 266 } 267 268 /* 269 * sysmon_power_daemon_task: 270 * 271 * Assign required power event members and sends a signal 272 * to the process to notify that an event was enqueued successfully. 273 */ 274 static int 275 sysmon_power_daemon_task(struct power_event_dictionary *ped, 276 void *pev_data, int event) 277 { 278 power_event_t pev; 279 int rv, error = 0; 280 281 if (!ped || !ped->dict || !pev_data) 282 return EINVAL; 283 284 mutex_enter(&sysmon_power_event_queue_mtx); 285 286 switch (event) { 287 /* 288 * Power switch events. 289 */ 290 case PSWITCH_EVENT_PRESSED: 291 case PSWITCH_EVENT_RELEASED: 292 { 293 294 struct sysmon_pswitch *pswitch = 295 (struct sysmon_pswitch *)pev_data; 296 297 pev.pev_type = POWER_EVENT_SWITCH_STATE_CHANGE; 298 #ifdef COMPAT_40 299 pev.pev_switch.psws_state = event; 300 pev.pev_switch.psws_type = pswitch->smpsw_type; 301 302 if (pswitch->smpsw_name) { 303 (void)strlcpy(pev.pev_switch.psws_name, 304 pswitch->smpsw_name, 305 sizeof(pev.pev_switch.psws_name)); 306 } 307 #endif 308 error = sysmon_power_make_dictionary(ped->dict, 309 pswitch, 310 event, 311 pev.pev_type); 312 if (error) { 313 mutex_exit(&sysmon_power_event_queue_mtx); 314 goto out; 315 } 316 317 break; 318 } 319 320 /* 321 * ENVSYS events. 322 */ 323 case PENVSYS_EVENT_NORMAL: 324 case PENVSYS_EVENT_CRITICAL: 325 case PENVSYS_EVENT_CRITUNDER: 326 case PENVSYS_EVENT_CRITOVER: 327 case PENVSYS_EVENT_WARNUNDER: 328 case PENVSYS_EVENT_WARNOVER: 329 case PENVSYS_EVENT_BATT_CRIT: 330 case PENVSYS_EVENT_BATT_WARN: 331 case PENVSYS_EVENT_BATT_HIGH: 332 case PENVSYS_EVENT_BATT_MAX: 333 case PENVSYS_EVENT_STATE_CHANGED: 334 case PENVSYS_EVENT_LOW_POWER: 335 { 336 struct penvsys_state *penvsys = 337 (struct penvsys_state *)pev_data; 338 339 pev.pev_type = POWER_EVENT_ENVSYS_STATE_CHANGE; 340 341 error = sysmon_power_make_dictionary(ped->dict, 342 penvsys, 343 event, 344 pev.pev_type); 345 if (error) { 346 mutex_exit(&sysmon_power_event_queue_mtx); 347 goto out; 348 } 349 350 break; 351 } 352 default: 353 error = ENOTTY; 354 mutex_exit(&sysmon_power_event_queue_mtx); 355 goto out; 356 } 357 358 /* 359 * Enqueue the event. 360 */ 361 rv = sysmon_queue_power_event(&pev); 362 if (rv == 0) { 363 printf("%s: WARNING: state change event %d lost; " 364 "queue full\n", __func__, pev.pev_type); 365 mutex_exit(&sysmon_power_event_queue_mtx); 366 error = EINVAL; 367 goto out; 368 } else { 369 /* 370 * Notify the daemon that an event is ready and its 371 * dictionary is ready to be fetched. 372 */ 373 ped->flags |= SYSMON_POWER_DICTIONARY_READY; 374 SIMPLEQ_INSERT_TAIL(&pev_dict_list, ped, pev_dict_head); 375 cv_broadcast(&sysmon_power_event_queue_cv); 376 mutex_exit(&sysmon_power_event_queue_mtx); 377 selnotify(&sysmon_power_event_queue_selinfo, 0, 0); 378 } 379 380 out: 381 return error; 382 } 383 384 /* 385 * sysmonopen_power: 386 * 387 * Open the system monitor device. 388 */ 389 int 390 sysmonopen_power(dev_t dev, int flag, int mode, struct lwp *l) 391 { 392 int error = 0; 393 394 mutex_enter(&sysmon_power_event_queue_mtx); 395 if (sysmon_power_daemon != NULL) 396 error = EBUSY; 397 else { 398 sysmon_power_daemon = l; 399 sysmon_power_event_queue_flush(); 400 } 401 mutex_exit(&sysmon_power_event_queue_mtx); 402 403 return error; 404 } 405 406 /* 407 * sysmonclose_power: 408 * 409 * Close the system monitor device. 410 */ 411 int 412 sysmonclose_power(dev_t dev, int flag, int mode, struct lwp *l) 413 { 414 int count; 415 416 mutex_enter(&sysmon_power_event_queue_mtx); 417 count = sysmon_power_event_queue_count; 418 sysmon_power_daemon = NULL; 419 sysmon_power_event_queue_flush(); 420 mutex_exit(&sysmon_power_event_queue_mtx); 421 422 if (count) 423 printf("WARNING: %d power event%s lost by exiting daemon\n", 424 count, count > 1 ? "s" : ""); 425 426 return 0; 427 } 428 429 /* 430 * sysmonread_power: 431 * 432 * Read the system monitor device. 433 */ 434 int 435 sysmonread_power(dev_t dev, struct uio *uio, int flags) 436 { 437 power_event_t pev; 438 int rv; 439 440 /* We only allow one event to be read at a time. */ 441 if (uio->uio_resid != POWER_EVENT_MSG_SIZE) 442 return EINVAL; 443 444 mutex_enter(&sysmon_power_event_queue_mtx); 445 for (;;) { 446 if (sysmon_get_power_event(&pev)) { 447 rv = uiomove(&pev, POWER_EVENT_MSG_SIZE, uio); 448 break; 449 } 450 451 if (flags & IO_NDELAY) { 452 rv = EWOULDBLOCK; 453 break; 454 } 455 456 cv_wait(&sysmon_power_event_queue_cv, 457 &sysmon_power_event_queue_mtx); 458 } 459 mutex_exit(&sysmon_power_event_queue_mtx); 460 461 return rv; 462 } 463 464 /* 465 * sysmonpoll_power: 466 * 467 * Poll the system monitor device. 468 */ 469 int 470 sysmonpoll_power(dev_t dev, int events, struct lwp *l) 471 { 472 int revents; 473 474 revents = events & (POLLOUT | POLLWRNORM); 475 476 /* Attempt to save some work. */ 477 if ((events & (POLLIN | POLLRDNORM)) == 0) 478 return revents; 479 480 mutex_enter(&sysmon_power_event_queue_mtx); 481 if (sysmon_power_event_queue_count) 482 revents |= events & (POLLIN | POLLRDNORM); 483 else 484 selrecord(l, &sysmon_power_event_queue_selinfo); 485 mutex_exit(&sysmon_power_event_queue_mtx); 486 487 return revents; 488 } 489 490 static void 491 filt_sysmon_power_rdetach(struct knote *kn) 492 { 493 494 mutex_enter(&sysmon_power_event_queue_mtx); 495 SLIST_REMOVE(&sysmon_power_event_queue_selinfo.sel_klist, 496 kn, knote, kn_selnext); 497 mutex_exit(&sysmon_power_event_queue_mtx); 498 } 499 500 static int 501 filt_sysmon_power_read(struct knote *kn, long hint) 502 { 503 504 mutex_enter(&sysmon_power_event_queue_mtx); 505 kn->kn_data = sysmon_power_event_queue_count; 506 mutex_exit(&sysmon_power_event_queue_mtx); 507 508 return kn->kn_data > 0; 509 } 510 511 static const struct filterops sysmon_power_read_filtops = 512 { 1, NULL, filt_sysmon_power_rdetach, filt_sysmon_power_read }; 513 514 static const struct filterops sysmon_power_write_filtops = 515 { 1, NULL, filt_sysmon_power_rdetach, filt_seltrue }; 516 517 /* 518 * sysmonkqfilter_power: 519 * 520 * Kqueue filter for the system monitor device. 521 */ 522 int 523 sysmonkqfilter_power(dev_t dev, struct knote *kn) 524 { 525 struct klist *klist; 526 527 switch (kn->kn_filter) { 528 case EVFILT_READ: 529 klist = &sysmon_power_event_queue_selinfo.sel_klist; 530 kn->kn_fop = &sysmon_power_read_filtops; 531 break; 532 533 case EVFILT_WRITE: 534 klist = &sysmon_power_event_queue_selinfo.sel_klist; 535 kn->kn_fop = &sysmon_power_write_filtops; 536 break; 537 538 default: 539 return EINVAL; 540 } 541 542 mutex_enter(&sysmon_power_event_queue_mtx); 543 SLIST_INSERT_HEAD(klist, kn, kn_selnext); 544 mutex_exit(&sysmon_power_event_queue_mtx); 545 546 return 0; 547 } 548 549 /* 550 * sysmonioctl_power: 551 * 552 * Perform a power management control request. 553 */ 554 int 555 sysmonioctl_power(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 556 { 557 int error = 0; 558 559 switch (cmd) { 560 case POWER_IOC_GET_TYPE: 561 case POWER_IOC_GET_TYPE_WITH_LOSSAGE: 562 { 563 struct power_type *power_type = (void *) data; 564 565 (void)strlcpy(power_type->power_type, 566 sysmon_power_type, 567 sizeof(power_type->power_type)); 568 break; 569 } 570 case POWER_EVENT_RECVDICT: 571 { 572 struct plistref *plist = (struct plistref *)data; 573 struct power_event_dictionary *ped; 574 575 /* 576 * Get the first dictionary enqueued and mark it 577 * as busy. 578 */ 579 mutex_enter(&sysmon_power_event_queue_mtx); 580 ped = SIMPLEQ_FIRST(&pev_dict_list); 581 if (!ped || !ped->dict) { 582 mutex_exit(&sysmon_power_event_queue_mtx); 583 error = ENOTSUP; 584 break; 585 } 586 587 if ((ped->flags & SYSMON_POWER_DICTIONARY_READY) == 0) { 588 mutex_exit(&sysmon_power_event_queue_mtx); 589 error = EINVAL; 590 break; 591 } 592 593 if (ped->flags & SYSMON_POWER_DICTIONARY_BUSY) { 594 mutex_exit(&sysmon_power_event_queue_mtx); 595 error = EBUSY; 596 break; 597 } 598 599 ped->flags |= SYSMON_POWER_DICTIONARY_BUSY; 600 mutex_exit(&sysmon_power_event_queue_mtx); 601 602 /* 603 * Send it now. 604 */ 605 error = prop_dictionary_copyout_ioctl(plist, 606 cmd, 607 ped->dict); 608 609 /* 610 * Remove the dictionary now that we don't need it. 611 */ 612 mutex_enter(&sysmon_power_event_queue_mtx); 613 ped->flags &= ~SYSMON_POWER_DICTIONARY_BUSY; 614 ped->flags &= ~SYSMON_POWER_DICTIONARY_READY; 615 SIMPLEQ_REMOVE_HEAD(&pev_dict_list, pev_dict_head); 616 mutex_exit(&sysmon_power_event_queue_mtx); 617 sysmon_power_destroy_dictionary(ped); 618 619 break; 620 } 621 default: 622 error = ENOTTY; 623 } 624 625 return error; 626 } 627 628 /* 629 * sysmon_power_make_dictionary: 630 * 631 * Adds the properties for an event in a dictionary. 632 */ 633 int 634 sysmon_power_make_dictionary(prop_dictionary_t dict, void *power_data, 635 int event, int type) 636 { 637 int i; 638 639 KASSERT(mutex_owned(&sysmon_power_event_queue_mtx)); 640 641 switch (type) { 642 /* 643 * create the dictionary for a power switch event. 644 */ 645 case POWER_EVENT_SWITCH_STATE_CHANGE: 646 { 647 const struct power_event_description *peevent = 648 pswitch_event_desc; 649 const struct power_event_description *petype = 650 pswitch_type_desc; 651 struct sysmon_pswitch *smpsw = 652 (struct sysmon_pswitch *)power_data; 653 const char *pwrtype = "pswitch"; 654 655 #define SETPROP(key, str) \ 656 do { \ 657 if ((str) != NULL && !prop_dictionary_set_cstring(dict, \ 658 (key), \ 659 (str))) { \ 660 printf("%s: failed to set %s\n", __func__, (str)); \ 661 return EINVAL; \ 662 } \ 663 } while (/* CONSTCOND */ 0) 664 665 666 SETPROP("driver-name", smpsw->smpsw_name); 667 668 for (i = 0; peevent[i].type != -1; i++) 669 if (peevent[i].type == event) 670 break; 671 672 SETPROP("powerd-event-name", peevent[i].desc); 673 674 for (i = 0; petype[i].type != -1; i++) 675 if (petype[i].type == smpsw->smpsw_type) 676 break; 677 678 SETPROP("powerd-script-name", petype[i].desc); 679 SETPROP("power-type", pwrtype); 680 break; 681 } 682 /* 683 * create a dictionary for power envsys event. 684 */ 685 case POWER_EVENT_ENVSYS_STATE_CHANGE: 686 { 687 const struct power_event_description *peevent = 688 penvsys_event_desc; 689 const struct power_event_description *petype = 690 penvsys_type_desc; 691 struct penvsys_state *pes = 692 (struct penvsys_state *)power_data; 693 const char *pwrtype = "envsys"; 694 695 SETPROP("driver-name", pes->pes_dvname); 696 SETPROP("sensor-name", pes->pes_sensname); 697 SETPROP("state-description", pes->pes_statedesc); 698 699 for (i = 0; peevent[i].type != -1; i++) 700 if (peevent[i].type == event) 701 break; 702 703 SETPROP("powerd-event-name", peevent[i].desc); 704 705 for (i = 0; petype[i].type != -1; i++) 706 if (petype[i].type == pes->pes_type) 707 break; 708 709 SETPROP("powerd-script-name", petype[i].desc); 710 SETPROP("power-type", pwrtype); 711 break; 712 } 713 default: 714 return ENOTSUP; 715 } 716 717 return 0; 718 } 719 720 /* 721 * sysmon_power_destroy_dictionary: 722 * 723 * Destroys a power_event_dictionary object and all its 724 * properties in the dictionary. 725 */ 726 static void 727 sysmon_power_destroy_dictionary(struct power_event_dictionary *ped) 728 { 729 prop_object_iterator_t iter; 730 prop_object_t obj; 731 732 KASSERT(ped != NULL); 733 KASSERT((ped->flags & SYSMON_POWER_DICTIONARY_BUSY) == 0); 734 735 iter = prop_dictionary_iterator(ped->dict); 736 if (iter == NULL) 737 return; 738 739 while ((obj = prop_object_iterator_next(iter)) != NULL) { 740 prop_dictionary_remove(ped->dict, 741 prop_dictionary_keysym_cstring_nocopy(obj)); 742 prop_object_iterator_reset(iter); 743 } 744 745 prop_object_iterator_release(iter); 746 prop_object_release(ped->dict); 747 748 kmem_free(ped, sizeof(*ped)); 749 } 750 751 /* 752 * sysmon_power_settype: 753 * 754 * Sets the back-end power management type. This information can 755 * be used by the power management daemon. 756 */ 757 void 758 sysmon_power_settype(const char *type) 759 { 760 761 /* 762 * Don't bother locking this; it's going to be set 763 * during autoconfiguration, and then only read from 764 * then on. 765 */ 766 (void)strlcpy(sysmon_power_type, type, sizeof(sysmon_power_type)); 767 } 768 769 #define PENVSYS_SHOWSTATE(str) \ 770 do { \ 771 printf("%s: %s limit on '%s'\n", \ 772 pes->pes_dvname, (str), pes->pes_sensname); \ 773 } while (/* CONSTCOND */ 0) 774 775 /* 776 * sysmon_penvsys_event: 777 * 778 * Puts an event onto the sysmon power queue and sends the 779 * appropriate event if the daemon is running, otherwise a 780 * message is shown. 781 */ 782 void 783 sysmon_penvsys_event(struct penvsys_state *pes, int event) 784 { 785 struct power_event_dictionary *ped; 786 const char *mystr = NULL; 787 788 KASSERT(pes != NULL); 789 790 rnd_add_uint32(&sysmon_rndsource, pes->pes_type); 791 792 if (sysmon_power_daemon != NULL) { 793 /* 794 * Create a dictionary for the new event. 795 */ 796 ped = kmem_zalloc(sizeof(*ped), KM_NOSLEEP); 797 if (!ped) 798 return; 799 ped->dict = prop_dictionary_create(); 800 801 if (sysmon_power_daemon_task(ped, pes, event) == 0) 802 return; 803 /* We failed */ 804 prop_object_release(ped->dict); 805 kmem_free(ped, sizeof(*ped)); 806 } 807 808 switch (pes->pes_type) { 809 case PENVSYS_TYPE_BATTERY: 810 switch (event) { 811 case PENVSYS_EVENT_LOW_POWER: 812 printf("sysmon: LOW POWER! SHUTTING DOWN.\n"); 813 cpu_reboot(RB_POWERDOWN, NULL); 814 break; 815 case PENVSYS_EVENT_STATE_CHANGED: 816 printf("%s: state changed on '%s' to '%s'\n", 817 pes->pes_dvname, pes->pes_sensname, 818 pes->pes_statedesc); 819 break; 820 case PENVSYS_EVENT_BATT_CRIT: 821 mystr = "critical capacity"; 822 PENVSYS_SHOWSTATE(mystr); 823 break; 824 case PENVSYS_EVENT_BATT_WARN: 825 mystr = "warning capacity"; 826 PENVSYS_SHOWSTATE(mystr); 827 break; 828 case PENVSYS_EVENT_BATT_HIGH: 829 mystr = "high capacity"; 830 PENVSYS_SHOWSTATE(mystr); 831 break; 832 case PENVSYS_EVENT_BATT_MAX: 833 mystr = "maximum capacity"; 834 PENVSYS_SHOWSTATE(mystr); 835 break; 836 case PENVSYS_EVENT_NORMAL: 837 printf("%s: normal capacity on '%s'\n", 838 pes->pes_dvname, pes->pes_sensname); 839 break; 840 } 841 break; 842 case PENVSYS_TYPE_FAN: 843 case PENVSYS_TYPE_INDICATOR: 844 case PENVSYS_TYPE_TEMP: 845 case PENVSYS_TYPE_POWER: 846 case PENVSYS_TYPE_RESISTANCE: 847 case PENVSYS_TYPE_VOLTAGE: 848 switch (event) { 849 case PENVSYS_EVENT_CRITICAL: 850 mystr = "critical"; 851 PENVSYS_SHOWSTATE(mystr); 852 break; 853 case PENVSYS_EVENT_CRITOVER: 854 mystr = "critical over"; 855 PENVSYS_SHOWSTATE(mystr); 856 break; 857 case PENVSYS_EVENT_CRITUNDER: 858 mystr = "critical under"; 859 PENVSYS_SHOWSTATE(mystr); 860 break; 861 case PENVSYS_EVENT_WARNOVER: 862 mystr = "warning over"; 863 PENVSYS_SHOWSTATE(mystr); 864 break; 865 case PENVSYS_EVENT_WARNUNDER: 866 mystr = "warning under"; 867 PENVSYS_SHOWSTATE(mystr); 868 break; 869 case PENVSYS_EVENT_NORMAL: 870 printf("%s: normal state on '%s'\n", 871 pes->pes_dvname, pes->pes_sensname); 872 break; 873 default: 874 printf("%s: unknown event\n", __func__); 875 } 876 break; 877 case PENVSYS_TYPE_DRIVE: 878 switch (event) { 879 case PENVSYS_EVENT_STATE_CHANGED: 880 printf("%s: state changed on '%s' to '%s'\n", 881 pes->pes_dvname, pes->pes_sensname, 882 pes->pes_statedesc); 883 break; 884 case PENVSYS_EVENT_NORMAL: 885 printf("%s: normal state on '%s' (%s)\n", 886 pes->pes_dvname, pes->pes_sensname, 887 pes->pes_statedesc); 888 break; 889 } 890 break; 891 default: 892 printf("%s: unknown power type\n", __func__); 893 break; 894 } 895 } 896 897 /* 898 * sysmon_pswitch_register: 899 * 900 * Register a power switch device. 901 */ 902 int 903 sysmon_pswitch_register(struct sysmon_pswitch *smpsw) 904 { 905 /* nada */ 906 return 0; 907 } 908 909 /* 910 * sysmon_pswitch_unregister: 911 * 912 * Unregister a power switch device. 913 */ 914 void 915 sysmon_pswitch_unregister(struct sysmon_pswitch *smpsw) 916 { 917 /* nada */ 918 } 919 920 /* 921 * sysmon_pswitch_event: 922 * 923 * Register an event on a power switch device. 924 */ 925 void 926 sysmon_pswitch_event(struct sysmon_pswitch *smpsw, int event) 927 { 928 struct power_event_dictionary *ped = NULL; 929 930 KASSERT(smpsw != NULL); 931 932 /* 933 * For pnp specific events, we don't care if the power daemon 934 * is running or not 935 */ 936 if (smpsw->smpsw_type == PSWITCH_TYPE_LID) { 937 switch (event) { 938 case PSWITCH_EVENT_PRESSED: 939 pmf_event_inject(NULL, PMFE_CHASSIS_LID_CLOSE); 940 break; 941 case PSWITCH_EVENT_RELEASED: 942 pmf_event_inject(NULL, PMFE_CHASSIS_LID_OPEN); 943 break; 944 default: 945 break; 946 } 947 } 948 949 if (sysmon_power_daemon != NULL) { 950 /* 951 * Create a new dictionary for the event. 952 */ 953 ped = kmem_zalloc(sizeof(*ped), KM_NOSLEEP); 954 if (!ped) 955 return; 956 ped->dict = prop_dictionary_create(); 957 958 if (sysmon_power_daemon_task(ped, smpsw, event) == 0) 959 return; 960 /* We failed */ 961 prop_object_release(ped->dict); 962 kmem_free(ped, sizeof(*ped)); 963 } 964 965 switch (smpsw->smpsw_type) { 966 case PSWITCH_TYPE_POWER: 967 if (event != PSWITCH_EVENT_PRESSED) { 968 /* just ignore it */ 969 return; 970 } 971 972 /* 973 * Attempt a somewhat graceful shutdown of the system, 974 * as if the user has issued a reboot(2) call with 975 * RB_POWERDOWN. 976 */ 977 printf("%s: power button pressed, shutting down!\n", 978 smpsw->smpsw_name); 979 cpu_reboot(RB_POWERDOWN, NULL); 980 break; 981 982 case PSWITCH_TYPE_RESET: 983 if (event != PSWITCH_EVENT_PRESSED) { 984 /* just ignore it */ 985 return; 986 } 987 988 /* 989 * Attempt a somewhat graceful reboot of the system, 990 * as if the user had issued a reboot(2) call. 991 */ 992 printf("%s: reset button pressed, rebooting!\n", 993 smpsw->smpsw_name); 994 cpu_reboot(0, NULL); 995 break; 996 997 case PSWITCH_TYPE_SLEEP: 998 if (event != PSWITCH_EVENT_PRESSED) { 999 /* just ignore it */ 1000 return; 1001 } 1002 1003 /* 1004 * Try to enter a "sleep" state. 1005 */ 1006 /* XXX */ 1007 printf("%s: sleep button pressed.\n", smpsw->smpsw_name); 1008 break; 1009 1010 case PSWITCH_TYPE_HOTKEY: 1011 /* 1012 * Eat up the event, there's nothing we can do 1013 */ 1014 break; 1015 1016 case PSWITCH_TYPE_LID: 1017 switch (event) { 1018 case PSWITCH_EVENT_PRESSED: 1019 /* 1020 * Try to enter a "standby" state. 1021 */ 1022 /* XXX */ 1023 printf("%s: lid closed.\n", smpsw->smpsw_name); 1024 break; 1025 1026 case PSWITCH_EVENT_RELEASED: 1027 /* 1028 * Come out of "standby" state. 1029 */ 1030 /* XXX */ 1031 printf("%s: lid opened.\n", smpsw->smpsw_name); 1032 break; 1033 1034 default: 1035 printf("%s: unknown lid switch event: %d\n", 1036 smpsw->smpsw_name, event); 1037 } 1038 break; 1039 1040 case PSWITCH_TYPE_ACADAPTER: 1041 switch (event) { 1042 case PSWITCH_EVENT_PRESSED: 1043 /* 1044 * Come out of power-save state. 1045 */ 1046 aprint_normal("%s: AC adapter online.\n", 1047 smpsw->smpsw_name); 1048 break; 1049 1050 case PSWITCH_EVENT_RELEASED: 1051 /* 1052 * Try to enter a power-save state. 1053 */ 1054 aprint_normal("%s: AC adapter offline.\n", 1055 smpsw->smpsw_name); 1056 break; 1057 } 1058 break; 1059 1060 } 1061 } 1062