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