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