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