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