1 2 /* 3 * CDDL HEADER START 4 * 5 * The contents of this file are subject to the terms of the 6 * Common Development and Distribution License (the "License"). 7 * You may not use this file except in compliance with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Power Button Driver 31 * 32 * This driver handles interrupt generated by the power button on 33 * platforms with "power" device node which has "button" property. 34 * Currently, these platforms are: 35 * 36 * ACPI-enabled x86/x64 platforms 37 * Ultra-5_10, Ultra-80, Sun-Blade-100, Sun-Blade-150, 38 * Sun-Blade-1500, Sun-Blade-2500, 39 * Sun-Fire-V210, Sun-Fire-V240, Netra-240 40 * 41 * Only one instance is allowed to attach. In order to know when 42 * an application that has opened the device is going away, a new 43 * minor clone is created for each open(9E) request. There are 44 * allocations for creating minor clones between 1 and 255. The ioctl 45 * interface is defined by pbio(7I) and approved as part of 46 * PSARC/1999/393 case. 47 */ 48 49 #include <sys/types.h> 50 #include <sys/conf.h> 51 #include <sys/ddi.h> 52 #include <sys/sunddi.h> 53 #include <sys/ddi_impldefs.h> 54 #include <sys/cmn_err.h> 55 #include <sys/errno.h> 56 #include <sys/modctl.h> 57 #include <sys/open.h> 58 #include <sys/stat.h> 59 #include <sys/poll.h> 60 #include <sys/pbio.h> 61 62 #if defined(__sparc) 63 #include <sys/machsystm.h> 64 #endif 65 66 #ifdef ACPI_POWER_BUTTON 67 68 #include <sys/acpi/acpi.h> 69 #include <sys/acpica.h> 70 71 #else 72 73 #include <sys/epic.h> 74 /* 75 * Some #defs that must be here as they differ for power.c 76 * and epic.c 77 */ 78 #define EPIC_REGS_OFFSET 0x00 79 #define EPIC_REGS_LEN 0x82 80 81 82 /* 83 * This flag, which is set for platforms, that have EPIC processor 84 * to process power button interrupt, helps in executing platform 85 * specific code. 86 */ 87 static char hasEPIC = B_FALSE; 88 #endif /* ACPI_POWER_BUTTON */ 89 90 /* 91 * Maximum number of clone minors that is allowed. This value 92 * is defined relatively low to save memory. 93 */ 94 #define POWER_MAX_CLONE 256 95 96 /* 97 * Minor number is instance << 8 + clone minor from range 1-255; clone 0 98 * is reserved for "original" minor. 99 */ 100 #define POWER_MINOR_TO_CLONE(minor) ((minor) & (POWER_MAX_CLONE - 1)) 101 102 /* 103 * Power Button Abort Delay 104 */ 105 #define ABORT_INCREMENT_DELAY 10 106 107 /* 108 * FWARC 2005/687: power device compatible property 109 */ 110 #define POWER_DEVICE_TYPE "power-device-type" 111 112 /* 113 * Driver global variables 114 */ 115 static void *power_state; 116 static int power_inst = -1; 117 118 static hrtime_t power_button_debounce = NANOSEC/MILLISEC*10; 119 static hrtime_t power_button_abort_interval = 1.5 * NANOSEC; 120 static int power_button_abort_presses = 3; 121 static int power_button_abort_enable = 1; 122 static int power_button_enable = 1; 123 124 static int power_button_pressed = 0; 125 static int power_button_cancel = 0; 126 static int power_button_timeouts = 0; 127 static int timeout_cancel = 0; 128 static int additional_presses = 0; 129 130 /* 131 * Function prototypes 132 */ 133 static int power_attach(dev_info_t *, ddi_attach_cmd_t); 134 static int power_detach(dev_info_t *, ddi_detach_cmd_t); 135 static int power_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 136 static int power_open(dev_t *, int, int, cred_t *); 137 static int power_close(dev_t, int, int, cred_t *); 138 static int power_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 139 static int power_chpoll(dev_t, short, int, short *, struct pollhead **); 140 #ifndef ACPI_POWER_BUTTON 141 static uint_t power_high_intr(caddr_t); 142 #endif 143 static uint_t power_soft_intr(caddr_t); 144 static uint_t power_issue_shutdown(caddr_t); 145 static void power_timeout(caddr_t); 146 static void power_log_message(void); 147 148 /* 149 * Structure used in the driver 150 */ 151 struct power_soft_state { 152 dev_info_t *dip; /* device info pointer */ 153 kmutex_t power_mutex; /* mutex lock */ 154 kmutex_t power_intr_mutex; /* interrupt mutex lock */ 155 ddi_iblock_cookie_t soft_iblock_cookie; /* holds interrupt cookie */ 156 ddi_iblock_cookie_t high_iblock_cookie; /* holds interrupt cookie */ 157 ddi_softintr_t softintr_id; /* soft interrupt id */ 158 uchar_t clones[POWER_MAX_CLONE]; /* array of minor clones */ 159 int monitor_on; /* clone monitoring the button event */ 160 /* clone 0 indicates no one is */ 161 /* monitoring the button event */ 162 pollhead_t pollhd; /* poll head struct */ 163 int events; /* bit map of occured events */ 164 int shutdown_pending; /* system shutdown in progress */ 165 #ifdef ACPI_POWER_BUTTON 166 boolean_t fixed_attached; /* true means fixed is attached */ 167 boolean_t gpe_attached; /* true means GPE is attached */ 168 ACPI_HANDLE button_obj; /* handle to device power button */ 169 #else 170 ddi_acc_handle_t power_rhandle; /* power button register handle */ 171 uint8_t *power_btn_reg; /* power button register address */ 172 uint8_t power_btn_bit; /* power button register bit */ 173 boolean_t power_regs_mapped; /* flag to tell if regs mapped */ 174 boolean_t power_btn_ioctl; /* flag to specify ioctl request */ 175 #endif 176 }; 177 178 #ifdef ACPI_POWER_BUTTON 179 static int power_attach_acpi(struct power_soft_state *softsp); 180 static void power_detach_acpi(struct power_soft_state *softsp); 181 static UINT32 power_acpi_fixed_event(void *ctx); 182 #else 183 static int power_setup_regs(struct power_soft_state *softsp); 184 static void power_free_regs(struct power_soft_state *softsp); 185 #endif /* ACPI_POWER_BUTTON */ 186 187 /* 188 * Configuration data structures 189 */ 190 static struct cb_ops power_cb_ops = { 191 power_open, /* open */ 192 power_close, /* close */ 193 nodev, /* strategy */ 194 nodev, /* print */ 195 nodev, /* dump */ 196 nodev, /* read */ 197 nodev, /* write */ 198 power_ioctl, /* ioctl */ 199 nodev, /* devmap */ 200 nodev, /* mmap */ 201 nodev, /* segmap */ 202 power_chpoll, /* poll */ 203 ddi_prop_op, /* cb_prop_op */ 204 NULL, /* streamtab */ 205 D_MP | D_NEW, /* Driver compatibility flag */ 206 CB_REV, /* rev */ 207 nodev, /* cb_aread */ 208 nodev /* cb_awrite */ 209 }; 210 211 static struct dev_ops power_ops = { 212 DEVO_REV, /* devo_rev, */ 213 0, /* refcnt */ 214 power_getinfo, /* getinfo */ 215 nulldev, /* identify */ 216 nulldev, /* probe */ 217 power_attach, /* attach */ 218 power_detach, /* detach */ 219 nodev, /* reset */ 220 &power_cb_ops, /* cb_ops */ 221 (struct bus_ops *)NULL, /* bus_ops */ 222 NULL /* power */ 223 }; 224 225 static struct modldrv modldrv = { 226 &mod_driverops, /* Type of module. This one is a driver */ 227 "power button driver v%I%", /* name of module */ 228 &power_ops, /* driver ops */ 229 }; 230 231 static struct modlinkage modlinkage = { 232 MODREV_1, 233 (void *)&modldrv, 234 NULL 235 }; 236 237 /* 238 * These are the module initialization routines. 239 */ 240 241 int 242 _init(void) 243 { 244 int error; 245 246 if ((error = ddi_soft_state_init(&power_state, 247 sizeof (struct power_soft_state), 0)) != 0) 248 return (error); 249 250 if ((error = mod_install(&modlinkage)) != 0) 251 ddi_soft_state_fini(&power_state); 252 253 return (error); 254 } 255 256 int 257 _fini(void) 258 { 259 int error; 260 261 if ((error = mod_remove(&modlinkage)) == 0) 262 ddi_soft_state_fini(&power_state); 263 264 return (error); 265 } 266 267 int 268 _info(struct modinfo *modinfop) 269 { 270 return (mod_info(&modlinkage, modinfop)); 271 } 272 273 /*ARGSUSED*/ 274 static int 275 power_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 276 void **result) 277 { 278 struct power_soft_state *softsp; 279 280 if (power_inst == -1) 281 return (DDI_FAILURE); 282 283 switch (infocmd) { 284 case DDI_INFO_DEVT2DEVINFO: 285 if ((softsp = ddi_get_soft_state(power_state, power_inst)) 286 == NULL) 287 return (DDI_FAILURE); 288 *result = (void *)softsp->dip; 289 return (DDI_SUCCESS); 290 291 case DDI_INFO_DEVT2INSTANCE: 292 *result = (void *)(uintptr_t)power_inst; 293 return (DDI_SUCCESS); 294 295 default: 296 return (DDI_FAILURE); 297 } 298 } 299 300 static int 301 power_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 302 { 303 struct power_soft_state *softsp; 304 305 switch (cmd) { 306 case DDI_ATTACH: 307 break; 308 case DDI_RESUME: 309 return (DDI_SUCCESS); 310 default: 311 return (DDI_FAILURE); 312 } 313 314 /* 315 * If the power node doesn't have "button" property, quietly 316 * fail to attach. 317 */ 318 if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 319 "button") == 0) 320 return (DDI_FAILURE); 321 322 if (power_inst != -1) 323 return (DDI_FAILURE); 324 325 power_inst = ddi_get_instance(dip); 326 327 if (ddi_soft_state_zalloc(power_state, power_inst) != DDI_SUCCESS) 328 return (DDI_FAILURE); 329 330 if (ddi_create_minor_node(dip, "power_button", S_IFCHR, 331 (power_inst << 8) + 0, "ddi_power_button", 0) != DDI_SUCCESS) 332 return (DDI_FAILURE); 333 334 softsp = ddi_get_soft_state(power_state, power_inst); 335 softsp->dip = dip; 336 337 #ifdef ACPI_POWER_BUTTON 338 (void) power_attach_acpi(softsp); 339 #else 340 if (power_setup_regs(softsp) != DDI_SUCCESS) { 341 cmn_err(CE_WARN, "power_attach: failed to setup registers"); 342 goto error; 343 } 344 345 if (ddi_get_iblock_cookie(dip, 0, 346 &softsp->high_iblock_cookie) != DDI_SUCCESS) { 347 cmn_err(CE_WARN, "power_attach: ddi_get_soft_iblock_cookie " 348 "failed."); 349 goto error; 350 } 351 mutex_init(&softsp->power_intr_mutex, NULL, MUTEX_DRIVER, 352 softsp->high_iblock_cookie); 353 354 if (ddi_add_intr(dip, 0, &softsp->high_iblock_cookie, NULL, 355 power_high_intr, (caddr_t)softsp) != DDI_SUCCESS) { 356 cmn_err(CE_WARN, "power_attach: failed to add high-level " 357 " interrupt handler."); 358 mutex_destroy(&softsp->power_intr_mutex); 359 goto error; 360 } 361 #endif /* ACPI_POWER_BUTTON */ 362 363 if (ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_LOW, 364 &softsp->soft_iblock_cookie) != DDI_SUCCESS) { 365 cmn_err(CE_WARN, "power_attach: ddi_get_soft_iblock_cookie " 366 "failed."); 367 mutex_destroy(&softsp->power_intr_mutex); 368 ddi_remove_intr(dip, 0, NULL); 369 goto error; 370 } 371 372 mutex_init(&softsp->power_mutex, NULL, MUTEX_DRIVER, 373 (void *)softsp->soft_iblock_cookie); 374 375 if (ddi_add_softintr(dip, DDI_SOFTINT_LOW, &softsp->softintr_id, 376 NULL, NULL, power_soft_intr, (caddr_t)softsp) != DDI_SUCCESS) { 377 cmn_err(CE_WARN, "power_attach: failed to add soft " 378 "interrupt handler."); 379 mutex_destroy(&softsp->power_mutex); 380 mutex_destroy(&softsp->power_intr_mutex); 381 ddi_remove_intr(dip, 0, NULL); 382 goto error; 383 } 384 385 ddi_report_dev(dip); 386 387 return (DDI_SUCCESS); 388 389 error: 390 #ifdef ACPI_POWER_BUTTON 391 /* 392 * detach ACPI power button 393 */ 394 power_detach_acpi(softsp); 395 #else 396 power_free_regs(softsp); 397 #endif /* ACPI_POWER_BUTTON */ 398 ddi_remove_minor_node(dip, "power_button"); 399 ddi_soft_state_free(power_state, power_inst); 400 return (DDI_FAILURE); 401 } 402 403 /*ARGSUSED*/ 404 /* 405 * This driver doesn't detach. 406 */ 407 static int 408 power_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 409 { 410 /* 411 * Since the "power" node has "reg" property, as part of 412 * the suspend operation, detach(9E) entry point is called. 413 * There is no state to save, since this register is used 414 * by OBP to power off the system and the state of the 415 * power off is preserved by hardware. 416 */ 417 return ((cmd == DDI_SUSPEND) ? DDI_SUCCESS : 418 DDI_FAILURE); 419 } 420 421 422 #ifndef ACPI_POWER_BUTTON 423 /* 424 * Handler for the high-level interrupt. 425 */ 426 static uint_t 427 power_high_intr(caddr_t arg) 428 { 429 struct power_soft_state *softsp = (struct power_soft_state *)arg; 430 ddi_acc_handle_t hdl = softsp->power_rhandle; 431 uint8_t reg; 432 433 hrtime_t tstamp; 434 static hrtime_t o_tstamp = 0; 435 static hrtime_t power_button_tstamp = 0; 436 static int power_button_cnt; 437 438 if (softsp->power_regs_mapped) { 439 mutex_enter(&softsp->power_intr_mutex); 440 441 /* Check if power button interrupt is delivered by EPIC HW */ 442 if (hasEPIC) { 443 /* read isr - first issue command */ 444 EPIC_WR(hdl, softsp->power_btn_reg, 445 EPIC_ATOM_INTR_READ); 446 /* next, read the reg */ 447 EPIC_RD(hdl, softsp->power_btn_reg, reg); 448 449 if (reg & EPIC_FIRE_INTERRUPT) { /* PB pressed */ 450 /* clear the interrupt */ 451 EPIC_WR(hdl, softsp->power_btn_reg, 452 EPIC_ATOM_INTR_CLEAR); 453 } else { 454 if (!softsp->power_btn_ioctl) { 455 mutex_exit(&softsp->power_intr_mutex); 456 return (DDI_INTR_CLAIMED); 457 } 458 softsp->power_btn_ioctl = B_FALSE; 459 } 460 } else { 461 reg = ddi_get8(hdl, softsp->power_btn_reg); 462 if (reg & softsp->power_btn_bit) { 463 reg &= softsp->power_btn_bit; 464 ddi_put8(hdl, softsp->power_btn_reg, reg); 465 (void) ddi_get8(hdl, softsp->power_btn_reg); 466 } else { 467 if (!softsp->power_btn_ioctl) { 468 mutex_exit(&softsp->power_intr_mutex); 469 return (DDI_INTR_CLAIMED); 470 } 471 softsp->power_btn_ioctl = B_FALSE; 472 } 473 } 474 mutex_exit(&softsp->power_intr_mutex); 475 } 476 477 tstamp = gethrtime(); 478 479 /* need to deal with power button debounce */ 480 if (o_tstamp && (tstamp - o_tstamp) < power_button_debounce) { 481 o_tstamp = tstamp; 482 return (DDI_INTR_CLAIMED); 483 } 484 o_tstamp = tstamp; 485 486 power_button_cnt++; 487 488 mutex_enter(&softsp->power_intr_mutex); 489 power_button_pressed++; 490 mutex_exit(&softsp->power_intr_mutex); 491 492 /* 493 * If power button abort is enabled and power button was pressed 494 * power_button_abort_presses times within power_button_abort_interval 495 * then call abort_sequence_enter(); 496 */ 497 if (power_button_abort_enable) { 498 if (power_button_abort_presses == 1 || 499 tstamp < (power_button_tstamp + 500 power_button_abort_interval)) { 501 if (power_button_cnt == power_button_abort_presses) { 502 mutex_enter(&softsp->power_intr_mutex); 503 power_button_cancel += power_button_timeouts; 504 power_button_pressed = 0; 505 mutex_exit(&softsp->power_intr_mutex); 506 power_button_cnt = 0; 507 abort_sequence_enter("Power Button Abort"); 508 return (DDI_INTR_CLAIMED); 509 } 510 } else { 511 power_button_cnt = 1; 512 power_button_tstamp = tstamp; 513 } 514 } 515 516 if (!power_button_enable) 517 return (DDI_INTR_CLAIMED); 518 519 /* post softint to issue timeout for power button action */ 520 if (softsp->softintr_id != NULL) 521 ddi_trigger_softintr(softsp->softintr_id); 522 523 return (DDI_INTR_CLAIMED); 524 } 525 #endif /* ifndef ACPI_POWER_BUTTON */ 526 527 /* 528 * Handle the softints.... 529 * 530 * If only one softint is posted for several button presses, record 531 * the number of additional presses just incase this was actually not quite 532 * an Abort sequence so that we can log this event later. 533 * 534 * Issue a timeout with a duration being a fraction larger than 535 * the specified Abort interval inorder to perform a power down if required. 536 */ 537 static uint_t 538 power_soft_intr(caddr_t arg) 539 { 540 struct power_soft_state *softsp = (struct power_soft_state *)arg; 541 542 if (!power_button_abort_enable) 543 return (power_issue_shutdown(arg)); 544 545 mutex_enter(&softsp->power_intr_mutex); 546 if (!power_button_pressed) { 547 mutex_exit(&softsp->power_intr_mutex); 548 return (DDI_INTR_CLAIMED); 549 } 550 551 /* 552 * Schedule a timeout to do the necessary 553 * work for shutdown, only one timeout for 554 * n presses if power button was pressed 555 * more than once before softint fired 556 */ 557 if (power_button_pressed > 1) 558 additional_presses += power_button_pressed - 1; 559 560 timeout_cancel = 0; 561 power_button_pressed = 0; 562 power_button_timeouts++; 563 mutex_exit(&softsp->power_intr_mutex); 564 (void) timeout((void(*)(void *))power_timeout, 565 softsp, NSEC_TO_TICK(power_button_abort_interval) + 566 ABORT_INCREMENT_DELAY); 567 568 return (DDI_INTR_CLAIMED); 569 } 570 571 /* 572 * Upon receiving a timeout the following is determined: 573 * 574 * If an Abort sequence was issued, then we cancel all outstanding timeouts 575 * and additional presses prior to the Abort sequence. 576 * 577 * If we had multiple timeouts issued and the abort sequence was not met, 578 * then we had more than one button press to power down the machine. We 579 * were probably trying to issue an abort. So log a message indicating this 580 * and cancel all outstanding timeouts. 581 * 582 * If we had just one timeout and the abort sequence was not met then 583 * we really did want to power down the machine, so call power_issue_shutdown() 584 * to do the work and schedule a power down 585 */ 586 static void 587 power_timeout(caddr_t arg) 588 { 589 struct power_soft_state *softsp = (struct power_soft_state *)arg; 590 static int first = 0; 591 592 /* 593 * Abort was generated cancel all outstanding power 594 * button timeouts 595 */ 596 mutex_enter(&softsp->power_intr_mutex); 597 if (power_button_cancel) { 598 power_button_cancel--; 599 power_button_timeouts--; 600 if (!first) { 601 first++; 602 additional_presses = 0; 603 } 604 mutex_exit(&softsp->power_intr_mutex); 605 return; 606 } 607 first = 0; 608 609 /* 610 * We get here if the timeout(s) have fired and they were 611 * not issued prior to an abort. 612 * 613 * If we had more than one press in the interval we were 614 * probably trying to issue an abort, but didnt press the 615 * required number within the interval. Hence cancel all 616 * timeouts and do not continue towards shutdown. 617 */ 618 if (!timeout_cancel) { 619 timeout_cancel = power_button_timeouts + 620 additional_presses; 621 622 power_button_timeouts--; 623 if (!power_button_timeouts) 624 additional_presses = 0; 625 626 if (timeout_cancel > 1) { 627 mutex_exit(&softsp->power_intr_mutex); 628 cmn_err(CE_NOTE, "Power Button pressed " 629 "%d times, cancelling all requests", 630 timeout_cancel); 631 return; 632 } 633 mutex_exit(&softsp->power_intr_mutex); 634 635 /* Go and do the work to request shutdown */ 636 (void) power_issue_shutdown((caddr_t)softsp); 637 return; 638 } 639 640 power_button_timeouts--; 641 if (!power_button_timeouts) 642 additional_presses = 0; 643 mutex_exit(&softsp->power_intr_mutex); 644 } 645 646 #ifdef ACPI_POWER_BUTTON 647 static void 648 do_shutdown(void) 649 { 650 proc_t *initpp; 651 652 /* 653 * If we're still booting and init(1) isn't set up yet, simply halt. 654 */ 655 mutex_enter(&pidlock); 656 initpp = prfind(P_INITPID); 657 mutex_exit(&pidlock); 658 if (initpp == NULL) { 659 extern void halt(char *); 660 halt("Power off the System"); /* just in case */ 661 } 662 663 /* 664 * else, graceful shutdown with inittab and all getting involved 665 */ 666 psignal(initpp, SIGPWR); 667 } 668 #endif 669 670 static uint_t 671 power_issue_shutdown(caddr_t arg) 672 { 673 struct power_soft_state *softsp = (struct power_soft_state *)arg; 674 675 mutex_enter(&softsp->power_mutex); 676 softsp->events |= PB_BUTTON_PRESS; 677 if (softsp->monitor_on != 0) { 678 mutex_exit(&softsp->power_mutex); 679 pollwakeup(&softsp->pollhd, POLLRDNORM); 680 pollwakeup(&softsp->pollhd, POLLIN); 681 return (DDI_INTR_CLAIMED); 682 } 683 684 if (!softsp->shutdown_pending) { 685 cmn_err(CE_WARN, "Power off requested from power button or " 686 "SC, powering down the system!"); 687 softsp->shutdown_pending = 1; 688 do_shutdown(); 689 690 /* 691 * Wait a while for "do_shutdown()" to shut down the system 692 * before logging an error message. 693 */ 694 (void) timeout((void(*)(void *))power_log_message, NULL, 695 100 * hz); 696 } 697 mutex_exit(&softsp->power_mutex); 698 699 return (DDI_INTR_CLAIMED); 700 } 701 702 /* 703 * Open the device. 704 */ 705 /*ARGSUSED*/ 706 static int 707 power_open(dev_t *devp, int openflags, int otyp, cred_t *credp) 708 { 709 struct power_soft_state *softsp; 710 int clone; 711 712 if (otyp != OTYP_CHR) 713 return (EINVAL); 714 715 if ((softsp = ddi_get_soft_state(power_state, power_inst)) == 716 NULL) 717 return (ENXIO); 718 719 mutex_enter(&softsp->power_mutex); 720 for (clone = 1; clone < POWER_MAX_CLONE; clone++) 721 if (!softsp->clones[clone]) 722 break; 723 724 if (clone == POWER_MAX_CLONE) { 725 cmn_err(CE_WARN, "power_open: No more allocation left " 726 "to create a clone minor."); 727 mutex_exit(&softsp->power_mutex); 728 return (ENXIO); 729 } 730 731 *devp = makedevice(getmajor(*devp), (power_inst << 8) + clone); 732 softsp->clones[clone] = 1; 733 mutex_exit(&softsp->power_mutex); 734 735 return (0); 736 } 737 738 /* 739 * Close the device. 740 */ 741 /*ARGSUSED*/ 742 static int 743 power_close(dev_t dev, int openflags, int otyp, cred_t *credp) 744 { 745 struct power_soft_state *softsp; 746 int clone; 747 748 if (otyp != OTYP_CHR) 749 return (EINVAL); 750 751 if ((softsp = ddi_get_soft_state(power_state, power_inst)) == 752 NULL) 753 return (ENXIO); 754 755 clone = POWER_MINOR_TO_CLONE(getminor(dev)); 756 mutex_enter(&softsp->power_mutex); 757 if (softsp->monitor_on == clone) 758 softsp->monitor_on = 0; 759 softsp->clones[clone] = 0; 760 mutex_exit(&softsp->power_mutex); 761 762 return (0); 763 } 764 765 /*ARGSUSED*/ 766 static int 767 power_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p, 768 int *rval_p) 769 { 770 struct power_soft_state *softsp; 771 int clone; 772 773 if ((softsp = ddi_get_soft_state(power_state, power_inst)) == 774 NULL) 775 return (ENXIO); 776 777 clone = POWER_MINOR_TO_CLONE(getminor(dev)); 778 switch (cmd) { 779 case PB_BEGIN_MONITOR: 780 mutex_enter(&softsp->power_mutex); 781 if (softsp->monitor_on) { 782 mutex_exit(&softsp->power_mutex); 783 return (EBUSY); 784 } 785 softsp->monitor_on = clone; 786 mutex_exit(&softsp->power_mutex); 787 return (0); 788 789 case PB_END_MONITOR: 790 mutex_enter(&softsp->power_mutex); 791 792 /* 793 * If PB_END_MONITOR is called without first 794 * calling PB_BEGIN_MONITOR, an error will be 795 * returned. 796 */ 797 if (!softsp->monitor_on) { 798 mutex_exit(&softsp->power_mutex); 799 return (ENXIO); 800 } 801 802 /* 803 * This clone is not monitoring the button. 804 */ 805 if (softsp->monitor_on != clone) { 806 mutex_exit(&softsp->power_mutex); 807 return (EINVAL); 808 } 809 softsp->monitor_on = 0; 810 mutex_exit(&softsp->power_mutex); 811 return (0); 812 813 case PB_GET_EVENTS: 814 mutex_enter(&softsp->power_mutex); 815 if (ddi_copyout((void *)&softsp->events, (void *)arg, 816 sizeof (int), mode) != 0) { 817 mutex_exit(&softsp->power_mutex); 818 return (EFAULT); 819 } 820 821 /* 822 * This ioctl returned the events detected since last 823 * call. Note that any application can get the events 824 * and clear the event register. 825 */ 826 softsp->events = 0; 827 mutex_exit(&softsp->power_mutex); 828 return (0); 829 830 /* 831 * This ioctl is used by the test suite. 832 */ 833 case PB_CREATE_BUTTON_EVENT: 834 #ifdef ACPI_POWER_BUTTON 835 (UINT32)power_acpi_fixed_event((void *)softsp); 836 #else 837 if (softsp->power_regs_mapped) { 838 mutex_enter(&softsp->power_intr_mutex); 839 softsp->power_btn_ioctl = B_TRUE; 840 mutex_exit(&softsp->power_intr_mutex); 841 } 842 (void) power_high_intr((caddr_t)softsp); 843 #endif /* ACPI_POWER_BUTTON */ 844 return (0); 845 846 default: 847 return (ENOTTY); 848 } 849 } 850 851 /*ARGSUSED*/ 852 static int 853 power_chpoll(dev_t dev, short events, int anyyet, 854 short *reventsp, struct pollhead **phpp) 855 { 856 struct power_soft_state *softsp; 857 858 if ((softsp = ddi_get_soft_state(power_state, power_inst)) == NULL) 859 return (ENXIO); 860 861 mutex_enter(&softsp->power_mutex); 862 *reventsp = 0; 863 if (softsp->events) 864 *reventsp = POLLRDNORM|POLLIN; 865 else { 866 if (!anyyet) 867 *phpp = &softsp->pollhd; 868 } 869 mutex_exit(&softsp->power_mutex); 870 871 return (0); 872 } 873 874 static void 875 power_log_message(void) 876 { 877 struct power_soft_state *softsp; 878 879 if ((softsp = ddi_get_soft_state(power_state, power_inst)) == NULL) { 880 cmn_err(CE_WARN, "Failed to get internal state!"); 881 return; 882 } 883 884 mutex_enter(&softsp->power_mutex); 885 softsp->shutdown_pending = 0; 886 cmn_err(CE_WARN, "Failed to shut down the system!"); 887 mutex_exit(&softsp->power_mutex); 888 } 889 890 #ifdef ACPI_POWER_BUTTON 891 /* 892 * Given a handle to a device object, locate a _PRW object 893 * if present and fetch the GPE info for this device object 894 */ 895 static ACPI_STATUS 896 power_get_prw_gpe(ACPI_HANDLE dev, ACPI_HANDLE *gpe_dev, UINT32 *gpe_num) 897 { 898 ACPI_BUFFER buf; 899 ACPI_STATUS status; 900 ACPI_HANDLE prw; 901 ACPI_OBJECT *gpe; 902 903 /* 904 * Evaluate _PRW if present 905 */ 906 status = AcpiGetHandle(dev, "_PRW", &prw); 907 if (status != AE_OK) 908 return (status); 909 buf.Length = ACPI_ALLOCATE_BUFFER; 910 status = AcpiEvaluateObjectTyped(prw, NULL, NULL, &buf, 911 ACPI_TYPE_PACKAGE); 912 if (status != AE_OK) 913 return (status); 914 915 /* 916 * Sanity-check the package; need at least two elements 917 */ 918 status = AE_ERROR; 919 if (((ACPI_OBJECT *)buf.Pointer)->Package.Count < 2) 920 goto done; 921 922 gpe = &((ACPI_OBJECT *)buf.Pointer)->Package.Elements[0]; 923 if (gpe->Type == ACPI_TYPE_INTEGER) { 924 *gpe_dev = NULL; 925 *gpe_num = gpe->Integer.Value; 926 status = AE_OK; 927 } else if (gpe->Type == ACPI_TYPE_PACKAGE) { 928 if ((gpe->Package.Count != 2) || 929 (gpe->Package.Elements[0].Type != ACPI_TYPE_DEVICE) || 930 (gpe->Package.Elements[1].Type != ACPI_TYPE_INTEGER)) 931 goto done; 932 *gpe_dev = gpe->Package.Elements[0].Reference.Handle; 933 *gpe_num = gpe->Package.Elements[1].Integer.Value; 934 status = AE_OK; 935 } 936 937 done: 938 AcpiOsFree(buf.Pointer); 939 return (status); 940 } 941 942 943 /* 944 * 945 */ 946 /*ARGSUSED*/ 947 static ACPI_STATUS 948 acpi_device(ACPI_HANDLE obj, UINT32 nesting, void *context, void **rv) 949 { 950 951 *((ACPI_HANDLE *)context) = obj; 952 return (AE_OK); 953 } 954 955 /* 956 * 957 */ 958 static ACPI_HANDLE 959 probe_acpi_pwrbutton() 960 { 961 ACPI_HANDLE obj = NULL; 962 963 (void) AcpiGetDevices("PNP0C0C", acpi_device, (void *)&obj, NULL); 964 return (obj); 965 } 966 967 static UINT32 968 power_acpi_fixed_event(void *ctx) 969 { 970 971 mutex_enter(&((struct power_soft_state *)ctx)->power_intr_mutex); 972 power_button_pressed++; 973 mutex_exit(&((struct power_soft_state *)ctx)->power_intr_mutex); 974 975 /* post softint to issue timeout for power button action */ 976 if (((struct power_soft_state *)ctx)->softintr_id != NULL) 977 ddi_trigger_softintr( 978 ((struct power_soft_state *)ctx)->softintr_id); 979 980 return (AE_OK); 981 } 982 983 /*ARGSUSED*/ 984 static void 985 power_acpi_notify_event(ACPI_HANDLE obj, UINT32 val, void *ctx) 986 { 987 if (val == 0x80) 988 (void) power_acpi_fixed_event(ctx); 989 } 990 991 /* 992 * 993 */ 994 static int 995 power_probe_method_button(struct power_soft_state *softsp) 996 { 997 ACPI_HANDLE button_obj; 998 UINT32 gpe_num; 999 ACPI_HANDLE gpe_dev; 1000 1001 button_obj = probe_acpi_pwrbutton(); 1002 softsp->button_obj = button_obj; /* remember obj */ 1003 if ((button_obj != NULL) && 1004 (power_get_prw_gpe(button_obj, &gpe_dev, &gpe_num) == AE_OK) && 1005 (AcpiSetGpeType(gpe_dev, gpe_num, ACPI_GPE_TYPE_WAKE_RUN) == 1006 AE_OK) && 1007 (AcpiEnableGpe(gpe_dev, gpe_num, ACPI_NOT_ISR) == AE_OK) && 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 FADT_DESCRIPTOR *fadt; 1021 1022 if (AcpiGetFirmwareTable(FADT_SIG, 1, ACPI_LOGICAL_ADDRESSING, 1023 (ACPI_TABLE_HEADER **) &fadt) != AE_OK) 1024 return (0); 1025 1026 if (!fadt->PwrButton) { 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 */ 1253