1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Power Button Driver 28 * 29 * This driver handles interrupt generated by the power button on 30 * platforms with "power" device node which has "button" property. 31 * Currently, these platforms are: 32 * 33 * ACPI-enabled x86/x64 platforms 34 * Ultra-5_10, Ultra-80, Sun-Blade-100, Sun-Blade-150, 35 * Sun-Blade-1500, Sun-Blade-2500, 36 * Sun-Fire-V210, Sun-Fire-V240, Netra-240 37 * 38 * Only one instance is allowed to attach. In order to know when 39 * an application that has opened the device is going away, a new 40 * minor clone is created for each open(9E) request. There are 41 * allocations for creating minor clones between 1 and 255. The ioctl 42 * interface is defined by pbio(7I) and approved as part of 43 * PSARC/1999/393 case. 44 */ 45 46 #include <sys/types.h> 47 #include <sys/conf.h> 48 #include <sys/ddi.h> 49 #include <sys/sunddi.h> 50 #include <sys/ddi_impldefs.h> 51 #include <sys/cmn_err.h> 52 #include <sys/errno.h> 53 #include <sys/modctl.h> 54 #include <sys/open.h> 55 #include <sys/stat.h> 56 #include <sys/poll.h> 57 #include <sys/pbio.h> 58 #include <sys/sysevent/eventdefs.h> 59 #include <sys/sysevent/pwrctl.h> 60 61 #if defined(__sparc) 62 #include <sys/machsystm.h> 63 #endif 64 65 #ifdef ACPI_POWER_BUTTON 66 67 #include <sys/acpi/acpi.h> 68 #include <sys/acpica.h> 69 70 #else 71 72 #include <sys/epic.h> 73 /* 74 * Some #defs that must be here as they differ for power.c 75 * and epic.c 76 */ 77 #define EPIC_REGS_OFFSET 0x00 78 #define EPIC_REGS_LEN 0x82 79 80 81 /* 82 * This flag, which is set for platforms, that have EPIC processor 83 * to process power button interrupt, helps in executing platform 84 * specific code. 85 */ 86 static char hasEPIC = B_FALSE; 87 #endif /* ACPI_POWER_BUTTON */ 88 89 /* 90 * Maximum number of clone minors that is allowed. This value 91 * is defined relatively low to save memory. 92 */ 93 #define POWER_MAX_CLONE 256 94 95 /* 96 * Minor number is instance << 8 + clone minor from range 1-255; clone 0 97 * is reserved for "original" minor. 98 */ 99 #define POWER_MINOR_TO_CLONE(minor) ((minor) & (POWER_MAX_CLONE - 1)) 100 101 /* 102 * Power Button Abort Delay 103 */ 104 #define ABORT_INCREMENT_DELAY 10 105 106 /* 107 * FWARC 2005/687: power device compatible property 108 */ 109 #define POWER_DEVICE_TYPE "power-device-type" 110 111 /* 112 * Driver global variables 113 */ 114 static void *power_state; 115 static int power_inst = -1; 116 117 static hrtime_t power_button_debounce = NANOSEC/MILLISEC*10; 118 static hrtime_t power_button_abort_interval = 1.5 * NANOSEC; 119 static int power_button_abort_presses = 3; 120 static int power_button_abort_enable = 1; 121 static int power_button_enable = 1; 122 123 static int power_button_pressed = 0; 124 static int power_button_cancel = 0; 125 static int power_button_timeouts = 0; 126 static int timeout_cancel = 0; 127 static int additional_presses = 0; 128 129 /* 130 * Function prototypes 131 */ 132 static int power_attach(dev_info_t *, ddi_attach_cmd_t); 133 static int power_detach(dev_info_t *, ddi_detach_cmd_t); 134 static int power_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 135 static int power_open(dev_t *, int, int, cred_t *); 136 static int power_close(dev_t, int, int, cred_t *); 137 static int power_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 138 static int power_chpoll(dev_t, short, int, short *, struct pollhead **); 139 #ifndef ACPI_POWER_BUTTON 140 static uint_t power_high_intr(caddr_t); 141 #endif 142 static uint_t power_soft_intr(caddr_t); 143 static uint_t power_issue_shutdown(caddr_t); 144 static void power_timeout(caddr_t); 145 static void power_log_message(void); 146 147 /* 148 * Structure used in the driver 149 */ 150 struct power_soft_state { 151 dev_info_t *dip; /* device info pointer */ 152 kmutex_t power_mutex; /* mutex lock */ 153 kmutex_t power_intr_mutex; /* interrupt mutex lock */ 154 ddi_iblock_cookie_t soft_iblock_cookie; /* holds interrupt cookie */ 155 ddi_iblock_cookie_t high_iblock_cookie; /* holds interrupt cookie */ 156 ddi_softintr_t softintr_id; /* soft interrupt id */ 157 uchar_t clones[POWER_MAX_CLONE]; /* array of minor clones */ 158 int monitor_on; /* clone monitoring the button event */ 159 /* clone 0 indicates no one is */ 160 /* monitoring the button event */ 161 pollhead_t pollhd; /* poll head struct */ 162 int events; /* bit map of occured events */ 163 int shutdown_pending; /* system shutdown in progress */ 164 #ifdef ACPI_POWER_BUTTON 165 boolean_t fixed_attached; /* true means fixed is attached */ 166 boolean_t gpe_attached; /* true means GPE is attached */ 167 ACPI_HANDLE button_obj; /* handle to device power button */ 168 #else 169 ddi_acc_handle_t power_rhandle; /* power button register handle */ 170 uint8_t *power_btn_reg; /* power button register address */ 171 uint8_t power_btn_bit; /* power button register bit */ 172 boolean_t power_regs_mapped; /* flag to tell if regs mapped */ 173 boolean_t power_btn_ioctl; /* flag to specify ioctl request */ 174 #endif 175 }; 176 177 static void power_gen_sysevent(struct power_soft_state *); 178 179 #ifdef ACPI_POWER_BUTTON 180 static int power_attach_acpi(struct power_soft_state *softsp); 181 static void power_detach_acpi(struct power_soft_state *softsp); 182 static UINT32 power_acpi_fixed_event(void *ctx); 183 #else 184 static int power_setup_regs(struct power_soft_state *softsp); 185 static void power_free_regs(struct power_soft_state *softsp); 186 #endif /* ACPI_POWER_BUTTON */ 187 188 /* 189 * Configuration data structures 190 */ 191 static struct cb_ops power_cb_ops = { 192 power_open, /* open */ 193 power_close, /* close */ 194 nodev, /* strategy */ 195 nodev, /* print */ 196 nodev, /* dump */ 197 nodev, /* read */ 198 nodev, /* write */ 199 power_ioctl, /* ioctl */ 200 nodev, /* devmap */ 201 nodev, /* mmap */ 202 nodev, /* segmap */ 203 power_chpoll, /* poll */ 204 ddi_prop_op, /* cb_prop_op */ 205 NULL, /* streamtab */ 206 D_MP | D_NEW, /* Driver compatibility flag */ 207 CB_REV, /* rev */ 208 nodev, /* cb_aread */ 209 nodev /* cb_awrite */ 210 }; 211 212 static struct dev_ops power_ops = { 213 DEVO_REV, /* devo_rev, */ 214 0, /* refcnt */ 215 power_getinfo, /* getinfo */ 216 nulldev, /* identify */ 217 nulldev, /* probe */ 218 power_attach, /* attach */ 219 power_detach, /* detach */ 220 nodev, /* reset */ 221 &power_cb_ops, /* cb_ops */ 222 (struct bus_ops *)NULL, /* bus_ops */ 223 NULL, /* power */ 224 ddi_quiesce_not_supported, /* devo_quiesce */ 225 }; 226 227 static struct modldrv modldrv = { 228 &mod_driverops, /* Type of module. This one is a driver */ 229 "power button driver", /* name of module */ 230 &power_ops, /* driver ops */ 231 }; 232 233 static struct modlinkage modlinkage = { 234 MODREV_1, 235 (void *)&modldrv, 236 NULL 237 }; 238 239 /* 240 * These are the module initialization routines. 241 */ 242 243 int 244 _init(void) 245 { 246 int error; 247 248 if ((error = ddi_soft_state_init(&power_state, 249 sizeof (struct power_soft_state), 0)) != 0) 250 return (error); 251 252 if ((error = mod_install(&modlinkage)) != 0) 253 ddi_soft_state_fini(&power_state); 254 255 return (error); 256 } 257 258 int 259 _fini(void) 260 { 261 int error; 262 263 if ((error = mod_remove(&modlinkage)) == 0) 264 ddi_soft_state_fini(&power_state); 265 266 return (error); 267 } 268 269 int 270 _info(struct modinfo *modinfop) 271 { 272 return (mod_info(&modlinkage, modinfop)); 273 } 274 275 /*ARGSUSED*/ 276 static int 277 power_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 278 void **result) 279 { 280 struct power_soft_state *softsp; 281 282 if (power_inst == -1) 283 return (DDI_FAILURE); 284 285 switch (infocmd) { 286 case DDI_INFO_DEVT2DEVINFO: 287 if ((softsp = ddi_get_soft_state(power_state, power_inst)) 288 == NULL) 289 return (DDI_FAILURE); 290 *result = (void *)softsp->dip; 291 return (DDI_SUCCESS); 292 293 case DDI_INFO_DEVT2INSTANCE: 294 *result = (void *)(uintptr_t)power_inst; 295 return (DDI_SUCCESS); 296 297 default: 298 return (DDI_FAILURE); 299 } 300 } 301 302 static int 303 power_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 304 { 305 struct power_soft_state *softsp; 306 307 switch (cmd) { 308 case DDI_ATTACH: 309 break; 310 case DDI_RESUME: 311 return (DDI_SUCCESS); 312 default: 313 return (DDI_FAILURE); 314 } 315 316 /* 317 * If the power node doesn't have "button" property, quietly 318 * fail to attach. 319 */ 320 if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 321 "button") == 0) 322 return (DDI_FAILURE); 323 324 if (power_inst != -1) 325 return (DDI_FAILURE); 326 327 power_inst = ddi_get_instance(dip); 328 329 if (ddi_soft_state_zalloc(power_state, power_inst) != DDI_SUCCESS) 330 return (DDI_FAILURE); 331 332 if (ddi_create_minor_node(dip, "power_button", S_IFCHR, 333 (power_inst << 8) + 0, "ddi_power_button", 0) != DDI_SUCCESS) 334 return (DDI_FAILURE); 335 336 softsp = ddi_get_soft_state(power_state, power_inst); 337 softsp->dip = dip; 338 339 #ifdef ACPI_POWER_BUTTON 340 (void) power_attach_acpi(softsp); 341 #else 342 if (power_setup_regs(softsp) != DDI_SUCCESS) { 343 cmn_err(CE_WARN, "power_attach: failed to setup registers"); 344 goto error; 345 } 346 347 if (ddi_get_iblock_cookie(dip, 0, 348 &softsp->high_iblock_cookie) != DDI_SUCCESS) { 349 cmn_err(CE_WARN, "power_attach: ddi_get_soft_iblock_cookie " 350 "failed."); 351 goto error; 352 } 353 mutex_init(&softsp->power_intr_mutex, NULL, MUTEX_DRIVER, 354 softsp->high_iblock_cookie); 355 356 if (ddi_add_intr(dip, 0, &softsp->high_iblock_cookie, NULL, 357 power_high_intr, (caddr_t)softsp) != DDI_SUCCESS) { 358 cmn_err(CE_WARN, "power_attach: failed to add high-level " 359 " interrupt handler."); 360 mutex_destroy(&softsp->power_intr_mutex); 361 goto error; 362 } 363 #endif /* ACPI_POWER_BUTTON */ 364 365 if (ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_LOW, 366 &softsp->soft_iblock_cookie) != DDI_SUCCESS) { 367 cmn_err(CE_WARN, "power_attach: ddi_get_soft_iblock_cookie " 368 "failed."); 369 mutex_destroy(&softsp->power_intr_mutex); 370 ddi_remove_intr(dip, 0, NULL); 371 goto error; 372 } 373 374 mutex_init(&softsp->power_mutex, NULL, MUTEX_DRIVER, 375 (void *)softsp->soft_iblock_cookie); 376 377 if (ddi_add_softintr(dip, DDI_SOFTINT_LOW, &softsp->softintr_id, 378 NULL, NULL, power_soft_intr, (caddr_t)softsp) != DDI_SUCCESS) { 379 cmn_err(CE_WARN, "power_attach: failed to add soft " 380 "interrupt handler."); 381 mutex_destroy(&softsp->power_mutex); 382 mutex_destroy(&softsp->power_intr_mutex); 383 ddi_remove_intr(dip, 0, NULL); 384 goto error; 385 } 386 387 ddi_report_dev(dip); 388 389 return (DDI_SUCCESS); 390 391 error: 392 #ifdef ACPI_POWER_BUTTON 393 /* 394 * detach ACPI power button 395 */ 396 power_detach_acpi(softsp); 397 #else 398 power_free_regs(softsp); 399 #endif /* ACPI_POWER_BUTTON */ 400 ddi_remove_minor_node(dip, "power_button"); 401 ddi_soft_state_free(power_state, power_inst); 402 return (DDI_FAILURE); 403 } 404 405 /*ARGSUSED*/ 406 /* 407 * This driver doesn't detach. 408 */ 409 static int 410 power_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 411 { 412 /* 413 * Since the "power" node has "reg" property, as part of 414 * the suspend operation, detach(9E) entry point is called. 415 * There is no state to save, since this register is used 416 * by OBP to power off the system and the state of the 417 * power off is preserved by hardware. 418 */ 419 return ((cmd == DDI_SUSPEND) ? DDI_SUCCESS : 420 DDI_FAILURE); 421 } 422 423 424 #ifndef ACPI_POWER_BUTTON 425 /* 426 * Handler for the high-level interrupt. 427 */ 428 static uint_t 429 power_high_intr(caddr_t arg) 430 { 431 struct power_soft_state *softsp = (struct power_soft_state *)arg; 432 ddi_acc_handle_t hdl = softsp->power_rhandle; 433 uint8_t reg; 434 435 hrtime_t tstamp; 436 static hrtime_t o_tstamp = 0; 437 static hrtime_t power_button_tstamp = 0; 438 static int power_button_cnt; 439 440 if (softsp->power_regs_mapped) { 441 mutex_enter(&softsp->power_intr_mutex); 442 443 /* Check if power button interrupt is delivered by EPIC HW */ 444 if (hasEPIC) { 445 /* read isr - first issue command */ 446 EPIC_WR(hdl, softsp->power_btn_reg, 447 EPIC_ATOM_INTR_READ); 448 /* next, read the reg */ 449 EPIC_RD(hdl, softsp->power_btn_reg, reg); 450 451 if (reg & EPIC_FIRE_INTERRUPT) { /* PB pressed */ 452 /* clear the interrupt */ 453 EPIC_WR(hdl, softsp->power_btn_reg, 454 EPIC_ATOM_INTR_CLEAR); 455 } else { 456 if (!softsp->power_btn_ioctl) { 457 mutex_exit(&softsp->power_intr_mutex); 458 return (DDI_INTR_CLAIMED); 459 } 460 softsp->power_btn_ioctl = B_FALSE; 461 } 462 } else { 463 reg = ddi_get8(hdl, softsp->power_btn_reg); 464 if (reg & softsp->power_btn_bit) { 465 reg &= softsp->power_btn_bit; 466 ddi_put8(hdl, softsp->power_btn_reg, reg); 467 (void) ddi_get8(hdl, softsp->power_btn_reg); 468 } else { 469 if (!softsp->power_btn_ioctl) { 470 mutex_exit(&softsp->power_intr_mutex); 471 return (DDI_INTR_CLAIMED); 472 } 473 softsp->power_btn_ioctl = B_FALSE; 474 } 475 } 476 mutex_exit(&softsp->power_intr_mutex); 477 } 478 479 tstamp = gethrtime(); 480 481 /* need to deal with power button debounce */ 482 if (o_tstamp && (tstamp - o_tstamp) < power_button_debounce) { 483 o_tstamp = tstamp; 484 return (DDI_INTR_CLAIMED); 485 } 486 o_tstamp = tstamp; 487 488 power_button_cnt++; 489 490 mutex_enter(&softsp->power_intr_mutex); 491 power_button_pressed++; 492 mutex_exit(&softsp->power_intr_mutex); 493 494 /* 495 * If power button abort is enabled and power button was pressed 496 * power_button_abort_presses times within power_button_abort_interval 497 * then call abort_sequence_enter(); 498 */ 499 if (power_button_abort_enable) { 500 if (power_button_abort_presses == 1 || 501 tstamp < (power_button_tstamp + 502 power_button_abort_interval)) { 503 if (power_button_cnt == power_button_abort_presses) { 504 mutex_enter(&softsp->power_intr_mutex); 505 power_button_cancel += power_button_timeouts; 506 power_button_pressed = 0; 507 mutex_exit(&softsp->power_intr_mutex); 508 power_button_cnt = 0; 509 abort_sequence_enter("Power Button Abort"); 510 return (DDI_INTR_CLAIMED); 511 } 512 } else { 513 power_button_cnt = 1; 514 power_button_tstamp = tstamp; 515 } 516 } 517 518 if (!power_button_enable) 519 return (DDI_INTR_CLAIMED); 520 521 /* post softint to issue timeout for power button action */ 522 if (softsp->softintr_id != NULL) 523 ddi_trigger_softintr(softsp->softintr_id); 524 525 return (DDI_INTR_CLAIMED); 526 } 527 #endif /* ifndef ACPI_POWER_BUTTON */ 528 529 /* 530 * Handle the softints.... 531 * 532 * If only one softint is posted for several button presses, record 533 * the number of additional presses just incase this was actually not quite 534 * an Abort sequence so that we can log this event later. 535 * 536 * Issue a timeout with a duration being a fraction larger than 537 * the specified Abort interval inorder to perform a power down if required. 538 */ 539 static uint_t 540 power_soft_intr(caddr_t arg) 541 { 542 struct power_soft_state *softsp = (struct power_soft_state *)arg; 543 544 if (!power_button_abort_enable) 545 return (power_issue_shutdown(arg)); 546 547 mutex_enter(&softsp->power_intr_mutex); 548 if (!power_button_pressed) { 549 mutex_exit(&softsp->power_intr_mutex); 550 return (DDI_INTR_CLAIMED); 551 } 552 553 /* 554 * Schedule a timeout to do the necessary 555 * work for shutdown, only one timeout for 556 * n presses if power button was pressed 557 * more than once before softint fired 558 */ 559 if (power_button_pressed > 1) 560 additional_presses += power_button_pressed - 1; 561 562 timeout_cancel = 0; 563 power_button_pressed = 0; 564 power_button_timeouts++; 565 mutex_exit(&softsp->power_intr_mutex); 566 (void) timeout((void(*)(void *))power_timeout, 567 softsp, NSEC_TO_TICK(power_button_abort_interval) + 568 ABORT_INCREMENT_DELAY); 569 570 return (DDI_INTR_CLAIMED); 571 } 572 573 /* 574 * Upon receiving a timeout the following is determined: 575 * 576 * If an Abort sequence was issued, then we cancel all outstanding timeouts 577 * and additional presses prior to the Abort sequence. 578 * 579 * If we had multiple timeouts issued and the abort sequence was not met, 580 * then we had more than one button press to power down the machine. We 581 * were probably trying to issue an abort. So log a message indicating this 582 * and cancel all outstanding timeouts. 583 * 584 * If we had just one timeout and the abort sequence was not met then 585 * we really did want to power down the machine, so call power_issue_shutdown() 586 * to do the work and schedule a power down 587 */ 588 static void 589 power_timeout(caddr_t arg) 590 { 591 struct power_soft_state *softsp = (struct power_soft_state *)arg; 592 static int first = 0; 593 594 /* 595 * Abort was generated cancel all outstanding power 596 * button timeouts 597 */ 598 mutex_enter(&softsp->power_intr_mutex); 599 if (power_button_cancel) { 600 power_button_cancel--; 601 power_button_timeouts--; 602 if (!first) { 603 first++; 604 additional_presses = 0; 605 } 606 mutex_exit(&softsp->power_intr_mutex); 607 return; 608 } 609 first = 0; 610 611 /* 612 * We get here if the timeout(s) have fired and they were 613 * not issued prior to an abort. 614 * 615 * If we had more than one press in the interval we were 616 * probably trying to issue an abort, but didnt press the 617 * required number within the interval. Hence cancel all 618 * timeouts and do not continue towards shutdown. 619 */ 620 if (!timeout_cancel) { 621 timeout_cancel = power_button_timeouts + 622 additional_presses; 623 624 power_button_timeouts--; 625 if (!power_button_timeouts) 626 additional_presses = 0; 627 628 if (timeout_cancel > 1) { 629 mutex_exit(&softsp->power_intr_mutex); 630 cmn_err(CE_NOTE, "Power Button pressed " 631 "%d times, cancelling all requests", 632 timeout_cancel); 633 return; 634 } 635 mutex_exit(&softsp->power_intr_mutex); 636 637 /* Go and do the work to request shutdown */ 638 (void) power_issue_shutdown((caddr_t)softsp); 639 return; 640 } 641 642 power_button_timeouts--; 643 if (!power_button_timeouts) 644 additional_presses = 0; 645 mutex_exit(&softsp->power_intr_mutex); 646 } 647 648 #ifdef ACPI_POWER_BUTTON 649 static void 650 do_shutdown(void) 651 { 652 proc_t *initpp; 653 654 /* 655 * If we're still booting and init(1) isn't set up yet, simply halt. 656 */ 657 mutex_enter(&pidlock); 658 initpp = prfind(P_INITPID); 659 mutex_exit(&pidlock); 660 if (initpp == NULL) { 661 extern void halt(char *); 662 halt("Power off the System"); /* just in case */ 663 } 664 665 /* 666 * else, graceful shutdown with inittab and all getting involved 667 */ 668 psignal(initpp, SIGPWR); 669 } 670 #endif 671 672 static uint_t 673 power_issue_shutdown(caddr_t arg) 674 { 675 struct power_soft_state *softsp = (struct power_soft_state *)arg; 676 677 mutex_enter(&softsp->power_mutex); 678 softsp->events |= PB_BUTTON_PRESS; 679 if (softsp->monitor_on != 0) { 680 mutex_exit(&softsp->power_mutex); 681 pollwakeup(&softsp->pollhd, POLLRDNORM); 682 pollwakeup(&softsp->pollhd, POLLIN); 683 power_gen_sysevent(softsp); 684 return (DDI_INTR_CLAIMED); 685 } 686 687 if (!softsp->shutdown_pending) { 688 cmn_err(CE_WARN, "Power off requested from power button or " 689 "SC, powering down the system!"); 690 softsp->shutdown_pending = 1; 691 do_shutdown(); 692 693 /* 694 * Wait a while for "do_shutdown()" to shut down the system 695 * before logging an error message. 696 */ 697 (void) timeout((void(*)(void *))power_log_message, NULL, 698 100 * hz); 699 } 700 mutex_exit(&softsp->power_mutex); 701 702 return (DDI_INTR_CLAIMED); 703 } 704 705 static void 706 power_gen_sysevent(struct power_soft_state *softsp) 707 { 708 nvlist_t *attr_list = NULL; 709 int err; 710 char pathname[MAXPATHLEN]; 711 char hid[9] = "\0"; 712 713 /* Allocate and build sysevent attribute list */ 714 err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, DDI_NOSLEEP); 715 if (err != 0) { 716 cmn_err(CE_WARN, 717 "cannot allocate memory for sysevent attributes\n"); 718 return; 719 } 720 721 #ifdef ACPI_POWER_BUTTON 722 /* Only control method power button has HID */ 723 if (softsp->gpe_attached) { 724 (void) strlcpy(hid, "PNP0C0C", sizeof (hid)); 725 } 726 #endif 727 728 err = nvlist_add_string(attr_list, PWRCTL_DEV_HID, hid); 729 if (err != 0) { 730 cmn_err(CE_WARN, 731 "Failed to add attr [%s] for %s/%s event", 732 PWRCTL_DEV_HID, EC_PWRCTL, ESC_PWRCTL_POWER_BUTTON); 733 nvlist_free(attr_list); 734 return; 735 } 736 737 (void) ddi_pathname(softsp->dip, pathname); 738 err = nvlist_add_string(attr_list, PWRCTL_DEV_PHYS_PATH, pathname); 739 if (err != 0) { 740 cmn_err(CE_WARN, 741 "Failed to add attr [%s] for %s/%s event", 742 PWRCTL_DEV_PHYS_PATH, EC_PWRCTL, ESC_PWRCTL_POWER_BUTTON); 743 nvlist_free(attr_list); 744 return; 745 } 746 747 /* Generate/log sysevent */ 748 err = ddi_log_sysevent(softsp->dip, DDI_VENDOR_SUNW, EC_PWRCTL, 749 ESC_PWRCTL_POWER_BUTTON, attr_list, NULL, DDI_NOSLEEP); 750 if (err != DDI_SUCCESS) { 751 cmn_err(CE_WARN, 752 "cannot log sysevent, err code %x\n", err); 753 } 754 755 nvlist_free(attr_list); 756 } 757 758 /* 759 * Open the device. 760 */ 761 /*ARGSUSED*/ 762 static int 763 power_open(dev_t *devp, int openflags, int otyp, cred_t *credp) 764 { 765 struct power_soft_state *softsp; 766 int clone; 767 768 if (otyp != OTYP_CHR) 769 return (EINVAL); 770 771 if ((softsp = ddi_get_soft_state(power_state, power_inst)) == 772 NULL) 773 return (ENXIO); 774 775 mutex_enter(&softsp->power_mutex); 776 for (clone = 1; clone < POWER_MAX_CLONE; clone++) 777 if (!softsp->clones[clone]) 778 break; 779 780 if (clone == POWER_MAX_CLONE) { 781 cmn_err(CE_WARN, "power_open: No more allocation left " 782 "to create a clone minor."); 783 mutex_exit(&softsp->power_mutex); 784 return (ENXIO); 785 } 786 787 *devp = makedevice(getmajor(*devp), (power_inst << 8) + clone); 788 softsp->clones[clone] = 1; 789 mutex_exit(&softsp->power_mutex); 790 791 return (0); 792 } 793 794 /* 795 * Close the device. 796 */ 797 /*ARGSUSED*/ 798 static int 799 power_close(dev_t dev, int openflags, int otyp, cred_t *credp) 800 { 801 struct power_soft_state *softsp; 802 int clone; 803 804 if (otyp != OTYP_CHR) 805 return (EINVAL); 806 807 if ((softsp = ddi_get_soft_state(power_state, power_inst)) == 808 NULL) 809 return (ENXIO); 810 811 clone = POWER_MINOR_TO_CLONE(getminor(dev)); 812 mutex_enter(&softsp->power_mutex); 813 if (softsp->monitor_on == clone) 814 softsp->monitor_on = 0; 815 softsp->clones[clone] = 0; 816 mutex_exit(&softsp->power_mutex); 817 818 return (0); 819 } 820 821 /*ARGSUSED*/ 822 static int 823 power_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p, 824 int *rval_p) 825 { 826 struct power_soft_state *softsp; 827 int clone; 828 829 if ((softsp = ddi_get_soft_state(power_state, power_inst)) == 830 NULL) 831 return (ENXIO); 832 833 clone = POWER_MINOR_TO_CLONE(getminor(dev)); 834 switch (cmd) { 835 case PB_BEGIN_MONITOR: 836 mutex_enter(&softsp->power_mutex); 837 if (softsp->monitor_on) { 838 mutex_exit(&softsp->power_mutex); 839 return (EBUSY); 840 } 841 softsp->monitor_on = clone; 842 mutex_exit(&softsp->power_mutex); 843 return (0); 844 845 case PB_END_MONITOR: 846 mutex_enter(&softsp->power_mutex); 847 848 /* 849 * If PB_END_MONITOR is called without first 850 * calling PB_BEGIN_MONITOR, an error will be 851 * returned. 852 */ 853 if (!softsp->monitor_on) { 854 mutex_exit(&softsp->power_mutex); 855 return (ENXIO); 856 } 857 858 /* 859 * This clone is not monitoring the button. 860 */ 861 if (softsp->monitor_on != clone) { 862 mutex_exit(&softsp->power_mutex); 863 return (EINVAL); 864 } 865 softsp->monitor_on = 0; 866 mutex_exit(&softsp->power_mutex); 867 return (0); 868 869 case PB_GET_EVENTS: 870 mutex_enter(&softsp->power_mutex); 871 if (ddi_copyout((void *)&softsp->events, (void *)arg, 872 sizeof (int), mode) != 0) { 873 mutex_exit(&softsp->power_mutex); 874 return (EFAULT); 875 } 876 877 /* 878 * This ioctl returned the events detected since last 879 * call. Note that any application can get the events 880 * and clear the event register. 881 */ 882 softsp->events = 0; 883 mutex_exit(&softsp->power_mutex); 884 return (0); 885 886 /* 887 * This ioctl is used by the test suite. 888 */ 889 case PB_CREATE_BUTTON_EVENT: 890 #ifdef ACPI_POWER_BUTTON 891 (UINT32)power_acpi_fixed_event((void *)softsp); 892 #else 893 if (softsp->power_regs_mapped) { 894 mutex_enter(&softsp->power_intr_mutex); 895 softsp->power_btn_ioctl = B_TRUE; 896 mutex_exit(&softsp->power_intr_mutex); 897 } 898 (void) power_high_intr((caddr_t)softsp); 899 #endif /* ACPI_POWER_BUTTON */ 900 return (0); 901 902 default: 903 return (ENOTTY); 904 } 905 } 906 907 /*ARGSUSED*/ 908 static int 909 power_chpoll(dev_t dev, short events, int anyyet, 910 short *reventsp, struct pollhead **phpp) 911 { 912 struct power_soft_state *softsp; 913 914 if ((softsp = ddi_get_soft_state(power_state, power_inst)) == NULL) 915 return (ENXIO); 916 917 mutex_enter(&softsp->power_mutex); 918 *reventsp = 0; 919 if (softsp->events) 920 *reventsp = POLLRDNORM|POLLIN; 921 else { 922 if (!anyyet) 923 *phpp = &softsp->pollhd; 924 } 925 mutex_exit(&softsp->power_mutex); 926 927 return (0); 928 } 929 930 static void 931 power_log_message(void) 932 { 933 struct power_soft_state *softsp; 934 935 if ((softsp = ddi_get_soft_state(power_state, power_inst)) == NULL) { 936 cmn_err(CE_WARN, "Failed to get internal state!"); 937 return; 938 } 939 940 mutex_enter(&softsp->power_mutex); 941 softsp->shutdown_pending = 0; 942 cmn_err(CE_WARN, "Failed to shut down the system!"); 943 mutex_exit(&softsp->power_mutex); 944 } 945 946 #ifdef ACPI_POWER_BUTTON 947 /* 948 * Given a handle to a device object, locate a _PRW object 949 * if present and fetch the GPE info for this device object 950 */ 951 static ACPI_STATUS 952 power_get_prw_gpe(ACPI_HANDLE dev, ACPI_HANDLE *gpe_dev, UINT32 *gpe_num) 953 { 954 ACPI_BUFFER buf; 955 ACPI_STATUS status; 956 ACPI_HANDLE prw; 957 ACPI_OBJECT *gpe; 958 959 /* 960 * Evaluate _PRW if present 961 */ 962 status = AcpiGetHandle(dev, "_PRW", &prw); 963 if (status != AE_OK) 964 return (status); 965 buf.Length = ACPI_ALLOCATE_BUFFER; 966 status = AcpiEvaluateObjectTyped(prw, NULL, NULL, &buf, 967 ACPI_TYPE_PACKAGE); 968 if (status != AE_OK) 969 return (status); 970 971 /* 972 * Sanity-check the package; need at least two elements 973 */ 974 status = AE_ERROR; 975 if (((ACPI_OBJECT *)buf.Pointer)->Package.Count < 2) 976 goto done; 977 978 gpe = &((ACPI_OBJECT *)buf.Pointer)->Package.Elements[0]; 979 if (gpe->Type == ACPI_TYPE_INTEGER) { 980 *gpe_dev = NULL; 981 *gpe_num = gpe->Integer.Value; 982 status = AE_OK; 983 } else if (gpe->Type == ACPI_TYPE_PACKAGE) { 984 if ((gpe->Package.Count != 2) || 985 (gpe->Package.Elements[0].Type != ACPI_TYPE_DEVICE) || 986 (gpe->Package.Elements[1].Type != ACPI_TYPE_INTEGER)) 987 goto done; 988 *gpe_dev = gpe->Package.Elements[0].Reference.Handle; 989 *gpe_num = gpe->Package.Elements[1].Integer.Value; 990 status = AE_OK; 991 } 992 993 done: 994 AcpiOsFree(buf.Pointer); 995 return (status); 996 } 997 998 999 /* 1000 * 1001 */ 1002 /*ARGSUSED*/ 1003 static ACPI_STATUS 1004 acpi_device(ACPI_HANDLE obj, UINT32 nesting, void *context, void **rv) 1005 { 1006 1007 *((ACPI_HANDLE *)context) = obj; 1008 return (AE_OK); 1009 } 1010 1011 /* 1012 * 1013 */ 1014 static ACPI_HANDLE 1015 probe_acpi_pwrbutton() 1016 { 1017 ACPI_HANDLE obj = NULL; 1018 1019 (void) AcpiGetDevices("PNP0C0C", acpi_device, (void *)&obj, NULL); 1020 return (obj); 1021 } 1022 1023 static UINT32 1024 power_acpi_fixed_event(void *ctx) 1025 { 1026 1027 mutex_enter(&((struct power_soft_state *)ctx)->power_intr_mutex); 1028 power_button_pressed++; 1029 mutex_exit(&((struct power_soft_state *)ctx)->power_intr_mutex); 1030 1031 /* post softint to issue timeout for power button action */ 1032 if (((struct power_soft_state *)ctx)->softintr_id != NULL) 1033 ddi_trigger_softintr( 1034 ((struct power_soft_state *)ctx)->softintr_id); 1035 1036 return (AE_OK); 1037 } 1038 1039 /*ARGSUSED*/ 1040 static void 1041 power_acpi_notify_event(ACPI_HANDLE obj, UINT32 val, void *ctx) 1042 { 1043 if (val == 0x80) 1044 (void) power_acpi_fixed_event(ctx); 1045 } 1046 1047 /* 1048 * 1049 */ 1050 static int 1051 power_probe_method_button(struct power_soft_state *softsp) 1052 { 1053 ACPI_HANDLE button_obj; 1054 UINT32 gpe_num; 1055 ACPI_HANDLE gpe_dev; 1056 1057 button_obj = probe_acpi_pwrbutton(); 1058 softsp->button_obj = button_obj; /* remember obj */ 1059 if ((button_obj != NULL) && 1060 (power_get_prw_gpe(button_obj, &gpe_dev, &gpe_num) == AE_OK) && 1061 (AcpiSetGpeType(gpe_dev, gpe_num, ACPI_GPE_TYPE_WAKE_RUN) == 1062 AE_OK) && 1063 (AcpiEnableGpe(gpe_dev, gpe_num, ACPI_NOT_ISR) == AE_OK) && 1064 (AcpiInstallNotifyHandler(button_obj, ACPI_DEVICE_NOTIFY, 1065 power_acpi_notify_event, (void*)softsp) == AE_OK)) 1066 return (1); 1067 return (0); 1068 } 1069 1070 /* 1071 * 1072 */ 1073 static int 1074 power_probe_fixed_button(struct power_soft_state *softsp) 1075 { 1076 ACPI_TABLE_FADT *fadt; 1077 1078 if (AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **) &fadt) != 1079 AE_OK) 1080 return (0); 1081 1082 if ((fadt->Flags & ACPI_FADT_POWER_BUTTON) == 0) { 1083 if (AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON, 1084 power_acpi_fixed_event, (void *)softsp) == AE_OK) 1085 return (1); 1086 } 1087 return (0); 1088 } 1089 1090 1091 /* 1092 * 1093 */ 1094 static int 1095 power_attach_acpi(struct power_soft_state *softsp) 1096 { 1097 1098 /* 1099 * If we've attached anything already, return an error 1100 */ 1101 if ((softsp->gpe_attached) || (softsp->fixed_attached)) 1102 return (DDI_FAILURE); 1103 1104 /* 1105 * attempt to attach both a fixed-event handler and a GPE 1106 * handler; remember what we got 1107 */ 1108 softsp->fixed_attached = (power_probe_fixed_button(softsp) != 0); 1109 softsp->gpe_attached = (power_probe_method_button(softsp) != 0); 1110 1111 /* 1112 * If we've attached anything now, return success 1113 */ 1114 if ((softsp->gpe_attached) || (softsp->fixed_attached)) 1115 return (DDI_SUCCESS); 1116 1117 return (DDI_FAILURE); 1118 } 1119 1120 /* 1121 * 1122 */ 1123 static void 1124 power_detach_acpi(struct power_soft_state *softsp) 1125 { 1126 if (softsp->gpe_attached) { 1127 if (AcpiRemoveNotifyHandler(softsp->button_obj, 1128 ACPI_DEVICE_NOTIFY, power_acpi_notify_event) != AE_OK) 1129 cmn_err(CE_WARN, "!power: failed to remove Notify" 1130 " handler"); 1131 } 1132 1133 if (softsp->fixed_attached) { 1134 if (AcpiRemoveFixedEventHandler(ACPI_EVENT_POWER_BUTTON, 1135 power_acpi_fixed_event) != AE_OK) 1136 cmn_err(CE_WARN, "!power: failed to remove Power" 1137 " Button handler"); 1138 } 1139 } 1140 1141 #else 1142 /* 1143 * Code for platforms that have EPIC processor for processing power 1144 * button interrupts. 1145 */ 1146 static int 1147 power_setup_epic_regs(dev_info_t *dip, struct power_soft_state *softsp) 1148 { 1149 ddi_device_acc_attr_t attr; 1150 uint8_t *reg_base; 1151 1152 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 1153 attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 1154 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 1155 if (ddi_regs_map_setup(dip, 0, (caddr_t *)®_base, 1156 EPIC_REGS_OFFSET, EPIC_REGS_LEN, &attr, 1157 &softsp->power_rhandle) != DDI_SUCCESS) { 1158 return (DDI_FAILURE); 1159 } 1160 1161 softsp->power_btn_reg = reg_base; 1162 softsp->power_regs_mapped = B_TRUE; 1163 1164 /* Clear power button interrupt first */ 1165 EPIC_WR(softsp->power_rhandle, softsp->power_btn_reg, 1166 EPIC_ATOM_INTR_CLEAR); 1167 1168 /* Enable EPIC interrupt for power button single press event */ 1169 EPIC_WR(softsp->power_rhandle, softsp->power_btn_reg, 1170 EPIC_ATOM_INTR_ENABLE); 1171 1172 /* 1173 * At this point, EPIC interrupt processing is fully initialised. 1174 */ 1175 hasEPIC = B_TRUE; 1176 return (DDI_SUCCESS); 1177 } 1178 1179 /* 1180 * 1181 * power button register definitions for acpi register on m1535d 1182 */ 1183 #define M1535D_PWR_BTN_REG_01 0x1 1184 #define M1535D_PWR_BTN_EVENT_FLAG 0x1 1185 1186 static int 1187 power_setup_m1535_regs(dev_info_t *dip, struct power_soft_state *softsp) 1188 { 1189 ddi_device_acc_attr_t attr; 1190 uint8_t *reg_base; 1191 1192 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 1193 attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 1194 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 1195 if (ddi_regs_map_setup(dip, 0, (caddr_t *)®_base, 0, 0, &attr, 1196 &softsp->power_rhandle) != DDI_SUCCESS) { 1197 return (DDI_FAILURE); 1198 } 1199 softsp->power_btn_reg = ®_base[M1535D_PWR_BTN_REG_01]; 1200 softsp->power_btn_bit = M1535D_PWR_BTN_EVENT_FLAG; 1201 softsp->power_regs_mapped = B_TRUE; 1202 return (DDI_SUCCESS); 1203 } 1204 1205 /* 1206 * MBC Fire/SSI Interrupt Status Register definitions 1207 */ 1208 #define FIRE_SSI_ISR 0x0 1209 #define FIRE_SSI_INTR_ENA 0x8 1210 #define FIRE_SSI_SHUTDOWN_REQ 0x4 1211 1212 static int 1213 power_setup_mbc_regs(dev_info_t *dip, struct power_soft_state *softsp) 1214 { 1215 ddi_device_acc_attr_t attr; 1216 uint8_t *reg_base; 1217 ddi_acc_handle_t hdl; 1218 uint8_t reg; 1219 1220 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 1221 attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 1222 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 1223 if (ddi_regs_map_setup(dip, 0, (caddr_t *)®_base, 0, 0, &attr, 1224 &softsp->power_rhandle) != DDI_SUCCESS) { 1225 return (DDI_FAILURE); 1226 } 1227 softsp->power_btn_reg = ®_base[FIRE_SSI_ISR]; 1228 softsp->power_btn_bit = FIRE_SSI_SHUTDOWN_REQ; 1229 hdl = softsp->power_rhandle; 1230 /* 1231 * Clear MBC Fire Power Button interrupt, if set. 1232 */ 1233 reg = ddi_get8(hdl, softsp->power_btn_reg); 1234 if (reg & softsp->power_btn_bit) { 1235 reg &= softsp->power_btn_bit; 1236 ddi_put8(hdl, softsp->power_btn_reg, reg); 1237 (void) ddi_get8(hdl, softsp->power_btn_reg); 1238 } 1239 /* 1240 * Enable MBC Fire Power Button interrupt. 1241 */ 1242 reg = ddi_get8(hdl, ®_base[FIRE_SSI_INTR_ENA]); 1243 reg |= FIRE_SSI_SHUTDOWN_REQ; 1244 ddi_put8(hdl, ®_base[FIRE_SSI_INTR_ENA], reg); 1245 1246 softsp->power_regs_mapped = B_TRUE; 1247 1248 return (DDI_SUCCESS); 1249 } 1250 1251 /* 1252 * Setup register map for the power button 1253 * NOTE:- we only map registers for platforms if 1254 * the OBP power device has any of the following 1255 * properties: 1256 * 1257 * a) Boston: power-device-type set to "SUNW,mbc" 1258 * b) Seattle: power-device-type set to "SUNW,pic18lf65j10" 1259 * c) Chalupa: compatible set to "ali1535d+-power" 1260 * 1261 * Cases (a) and (b) are defined in FWARC 2005/687. 1262 * If none of the above conditions are true, then we 1263 * do not need to map in any registers, and this 1264 * function can simply return DDI_SUCCESS. 1265 */ 1266 static int 1267 power_setup_regs(struct power_soft_state *softsp) 1268 { 1269 char *binding_name; 1270 char *power_type = NULL; 1271 int retval = DDI_SUCCESS; 1272 1273 softsp->power_regs_mapped = B_FALSE; 1274 softsp->power_btn_ioctl = B_FALSE; 1275 binding_name = ddi_binding_name(softsp->dip); 1276 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, softsp->dip, 1277 DDI_PROP_DONTPASS, POWER_DEVICE_TYPE, 1278 &power_type) == DDI_PROP_SUCCESS) { 1279 if (strcmp(power_type, "SUNW,mbc") == 0) { 1280 retval = power_setup_mbc_regs(softsp->dip, softsp); 1281 } else if (strcmp(power_type, "SUNW,pic18lf65j10") == 0) { 1282 retval = power_setup_epic_regs(softsp->dip, softsp); 1283 } else { 1284 cmn_err(CE_WARN, "unexpected power-device-type: %s\n", 1285 power_type); 1286 retval = DDI_FAILURE; 1287 } 1288 ddi_prop_free(power_type); 1289 } else if (strcmp(binding_name, "ali1535d+-power") == 0) { 1290 retval = power_setup_m1535_regs(softsp->dip, softsp); 1291 } 1292 1293 /* 1294 * If power-device-type does not exist AND the binding name is not 1295 * "ali1535d+-power", that means there is no additional HW and hence 1296 * no extra processing is necessary. In that case, retval should still 1297 * be set to its initial value of DDI_SUCCESS. 1298 */ 1299 return (retval); 1300 } 1301 1302 static void 1303 power_free_regs(struct power_soft_state *softsp) 1304 { 1305 if (softsp->power_regs_mapped) 1306 ddi_regs_map_free(&softsp->power_rhandle); 1307 } 1308 #endif /* ACPI_POWER_BUTTON */ 1309