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