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