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