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