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