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