Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/acpica/acpi.c
Show First 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | |||||
#include <sys/sbuf.h> | #include <sys/sbuf.h> | ||||
#include <sys/sched.h> | #include <sys/sched.h> | ||||
#include <sys/smp.h> | #include <sys/smp.h> | ||||
#include <sys/timetc.h> | #include <sys/timetc.h> | ||||
#if defined(__i386__) || defined(__amd64__) | #if defined(__i386__) || defined(__amd64__) | ||||
#include <machine/clock.h> | #include <machine/clock.h> | ||||
#include <machine/pci_cfgreg.h> | #include <machine/pci_cfgreg.h> | ||||
#include <machine/intr_machdep.h> | |||||
#endif | #endif | ||||
#include <machine/resource.h> | #include <machine/resource.h> | ||||
#include <machine/bus.h> | #include <machine/bus.h> | ||||
#include <sys/rman.h> | #include <sys/rman.h> | ||||
#include <isa/isavar.h> | #include <isa/isavar.h> | ||||
#include <isa/pnpvar.h> | #include <isa/pnpvar.h> | ||||
#include <contrib/dev/acpica/include/acpi.h> | #include <contrib/dev/acpica/include/acpi.h> | ||||
Show All 25 Lines | static struct cdevsw acpi_cdevsw = { | ||||
.d_name = "acpi", | .d_name = "acpi", | ||||
}; | }; | ||||
struct acpi_interface { | struct acpi_interface { | ||||
ACPI_STRING *data; | ACPI_STRING *data; | ||||
int num; | int num; | ||||
}; | }; | ||||
enum s2idle_enable { | |||||
POWER_BUTTON_S2I, | |||||
SLEEP_BUTTON_S2I, | |||||
LID_SWITCH_S2I, | |||||
STANDBY_S2I, | |||||
SUSPEND_S2I | |||||
}; | |||||
static char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL }; | static char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL }; | ||||
static char *pcilink_ids[] = { "PNP0C0F", NULL }; | static char *pcilink_ids[] = { "PNP0C0F", NULL }; | ||||
/* Global mutex for locking access to the ACPI subsystem. */ | /* Global mutex for locking access to the ACPI subsystem. */ | ||||
struct mtx acpi_mutex; | struct mtx acpi_mutex; | ||||
struct callout acpi_sleep_timer; | struct callout acpi_sleep_timer; | ||||
/* Bitmap of device quirks. */ | /* Bitmap of device quirks. */ | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | |||||
static int acpi_isa_pnp_probe(device_t bus, device_t child, | static int acpi_isa_pnp_probe(device_t bus, device_t child, | ||||
struct isa_pnp_id *ids); | struct isa_pnp_id *ids); | ||||
static void acpi_probe_children(device_t bus); | static void acpi_probe_children(device_t bus); | ||||
static void acpi_probe_order(ACPI_HANDLE handle, int *order); | static void acpi_probe_order(ACPI_HANDLE handle, int *order); | ||||
static ACPI_STATUS acpi_probe_child(ACPI_HANDLE handle, UINT32 level, | static ACPI_STATUS acpi_probe_child(ACPI_HANDLE handle, UINT32 level, | ||||
void *context, void **status); | void *context, void **status); | ||||
static void acpi_sleep_enable(void *arg); | static void acpi_sleep_enable(void *arg); | ||||
static ACPI_STATUS acpi_sleep_disable(struct acpi_softc *sc); | static ACPI_STATUS acpi_sleep_disable(struct acpi_softc *sc); | ||||
static ACPI_STATUS acpi_EnterSleepState(struct acpi_softc *sc, int state); | static ACPI_STATUS acpi_EnterSleepState(struct acpi_softc *sc, enum sleep_type stype); | ||||
static void acpi_shutdown_final(void *arg, int howto); | static void acpi_shutdown_final(void *arg, int howto); | ||||
static void acpi_enable_fixed_events(struct acpi_softc *sc); | static void acpi_enable_fixed_events(struct acpi_softc *sc); | ||||
static BOOLEAN acpi_has_hid(ACPI_HANDLE handle); | static BOOLEAN acpi_has_hid(ACPI_HANDLE handle); | ||||
static void acpi_resync_clock(struct acpi_softc *sc); | static void acpi_resync_clock(struct acpi_softc *sc); | ||||
static int acpi_wake_sleep_prep(ACPI_HANDLE handle, int sstate); | static int acpi_wake_sleep_prep(ACPI_HANDLE handle, int sstate); | ||||
static int acpi_wake_run_prep(ACPI_HANDLE handle, int sstate); | static int acpi_wake_run_prep(ACPI_HANDLE handle, int sstate); | ||||
static int acpi_wake_prep_walk(int sstate); | static int acpi_wake_prep_walk(int sstate); | ||||
static int acpi_wake_sysctl_walk(device_t dev); | static int acpi_wake_sysctl_walk(device_t dev); | ||||
static int acpi_wake_set_sysctl(SYSCTL_HANDLER_ARGS); | static int acpi_wake_set_sysctl(SYSCTL_HANDLER_ARGS); | ||||
static void acpi_system_eventhandler_sleep(void *arg, int state); | static void acpi_system_eventhandler_sleep(void *arg, enum sleep_type type); | ||||
static void acpi_system_eventhandler_wakeup(void *arg, int state); | static void acpi_system_eventhandler_wakeup(void *arg, enum sleep_type type); | ||||
static int acpi_stype2sstate(enum sleep_type type); | |||||
static int acpi_sname2sstate(const char *sname); | static int acpi_sname2sstate(const char *sname); | ||||
static const char *acpi_sstate2sname(int sstate); | static const char *acpi_sstate2sname(int sstate); | ||||
static int acpi_supported_sleep_state_sysctl(SYSCTL_HANDLER_ARGS); | static int acpi_supported_sleep_state_sysctl(SYSCTL_HANDLER_ARGS); | ||||
static int acpi_sleep_state_sysctl(SYSCTL_HANDLER_ARGS); | static int acpi_sleep_state_sysctl(SYSCTL_HANDLER_ARGS); | ||||
static int acpi_debug_objects_sysctl(SYSCTL_HANDLER_ARGS); | static int acpi_debug_objects_sysctl(SYSCTL_HANDLER_ARGS); | ||||
static int acpi_pm_func(u_long cmd, void *arg, ...); | static int acpi_pm_func(u_long cmd, void *arg, ...); | ||||
static int acpi_child_location_str_method(device_t acdev, device_t child, | static int acpi_child_location_str_method(device_t acdev, device_t child, | ||||
char *buf, size_t buflen); | char *buf, size_t buflen); | ||||
▲ Show 20 Lines • Show All 376 Lines • ▼ Show 20 Lines | sc->acpi_sysctl_tree = SYSCTL_ADD_NODE(&sc->acpi_sysctl_ctx, | ||||
SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, | SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, | ||||
device_get_name(dev), CTLFLAG_RD, 0, ""); | device_get_name(dev), CTLFLAG_RD, 0, ""); | ||||
SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), | SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), | ||||
OID_AUTO, "supported_sleep_state", CTLTYPE_STRING | CTLFLAG_RD, | OID_AUTO, "supported_sleep_state", CTLTYPE_STRING | CTLFLAG_RD, | ||||
0, 0, acpi_supported_sleep_state_sysctl, "A", | 0, 0, acpi_supported_sleep_state_sysctl, "A", | ||||
"List supported ACPI sleep states."); | "List supported ACPI sleep states."); | ||||
SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), | SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), | ||||
OID_AUTO, "power_button_state", CTLTYPE_STRING | CTLFLAG_RW, | OID_AUTO, "power_button_state", CTLTYPE_STRING | CTLFLAG_RW, | ||||
&sc->acpi_power_button_sx, 0, acpi_sleep_state_sysctl, "A", | &sc->acpi_power_button.sx, POWER_BUTTON_S2I, acpi_sleep_state_sysctl, | ||||
"Power button ACPI sleep state."); | "A", "Power button ACPI sleep state."); | ||||
SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), | SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), | ||||
OID_AUTO, "sleep_button_state", CTLTYPE_STRING | CTLFLAG_RW, | OID_AUTO, "sleep_button_state", CTLTYPE_STRING | CTLFLAG_RW, | ||||
&sc->acpi_sleep_button_sx, 0, acpi_sleep_state_sysctl, "A", | &sc->acpi_sleep_button.sx, SLEEP_BUTTON_S2I, acpi_sleep_state_sysctl, | ||||
"Sleep button ACPI sleep state."); | "A", "Sleep button ACPI sleep state."); | ||||
SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), | SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), | ||||
OID_AUTO, "lid_switch_state", CTLTYPE_STRING | CTLFLAG_RW, | OID_AUTO, "lid_switch_state", CTLTYPE_STRING | CTLFLAG_RW, | ||||
&sc->acpi_lid_switch_sx, 0, acpi_sleep_state_sysctl, "A", | &sc->acpi_lid_switch.sx, LID_SWITCH_S2I, acpi_sleep_state_sysctl, "A", | ||||
"Lid ACPI sleep state. Set to S3 if you want to suspend your laptop when close the Lid."); | "Lid ACPI sleep state. Set to S3 if you want to suspend your laptop when close the Lid."); | ||||
SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), | SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), | ||||
OID_AUTO, "standby_state", CTLTYPE_STRING | CTLFLAG_RW, | OID_AUTO, "standby_state", CTLTYPE_STRING | CTLFLAG_RW, | ||||
&sc->acpi_standby_sx, 0, acpi_sleep_state_sysctl, "A", ""); | &sc->acpi_standby.sx, STANDBY_S2I, acpi_sleep_state_sysctl, "A", ""); | ||||
SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), | SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), | ||||
OID_AUTO, "suspend_state", CTLTYPE_STRING | CTLFLAG_RW, | OID_AUTO, "suspend_state", CTLTYPE_STRING | CTLFLAG_RW, | ||||
&sc->acpi_suspend_sx, 0, acpi_sleep_state_sysctl, "A", ""); | &sc->acpi_suspend.sx, SUSPEND_S2I, acpi_sleep_state_sysctl, "A", ""); | ||||
SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), | SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), | ||||
OID_AUTO, "sleep_delay", CTLFLAG_RW, &sc->acpi_sleep_delay, 0, | OID_AUTO, "sleep_delay", CTLFLAG_RW, &sc->acpi_sleep_delay, 0, | ||||
"sleep delay in seconds"); | "sleep delay in seconds"); | ||||
SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), | SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), | ||||
OID_AUTO, "s4bios", CTLFLAG_RW, &sc->acpi_s4bios, 0, "S4BIOS mode"); | OID_AUTO, "s4bios", CTLFLAG_RW, &sc->acpi_s4bios, 0, "S4BIOS mode"); | ||||
SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), | SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), | ||||
OID_AUTO, "verbose", CTLFLAG_RW, &sc->acpi_verbose, 0, "verbose mode"); | OID_AUTO, "verbose", CTLFLAG_RW, &sc->acpi_verbose, 0, "verbose mode"); | ||||
SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), | SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), | ||||
Show All 33 Lines | if (ACPI_SUCCESS(AcpiEvaluateObject(ACPI_ROOT_OBJECT, | ||||
__DECONST(char *, AcpiGbl_SleepStateNames[state]), NULL, NULL)) && | __DECONST(char *, AcpiGbl_SleepStateNames[state]), NULL, NULL)) && | ||||
ACPI_SUCCESS(AcpiGetSleepTypeData(state, &TypeA, &TypeB))) | ACPI_SUCCESS(AcpiGetSleepTypeData(state, &TypeA, &TypeB))) | ||||
acpi_sleep_states[state] = TRUE; | acpi_sleep_states[state] = TRUE; | ||||
/* | /* | ||||
* Dispatch the default sleep state to devices. The lid switch is set | * Dispatch the default sleep state to devices. The lid switch is set | ||||
* to UNKNOWN by default to avoid surprising users. | * to UNKNOWN by default to avoid surprising users. | ||||
*/ | */ | ||||
sc->acpi_power_button_sx = acpi_sleep_states[ACPI_STATE_S5] ? | sc->acpi_power_button.sx = acpi_sleep_states[ACPI_STATE_S5] ? | ||||
ACPI_STATE_S5 : ACPI_STATE_UNKNOWN; | ACPI_STATE_S5 : ACPI_STATE_UNKNOWN; | ||||
sc->acpi_lid_switch_sx = ACPI_STATE_UNKNOWN; | sc->acpi_lid_switch.sx = ACPI_STATE_UNKNOWN; | ||||
sc->acpi_standby_sx = acpi_sleep_states[ACPI_STATE_S1] ? | sc->acpi_standby.sx = acpi_sleep_states[ACPI_STATE_S1] ? | ||||
ACPI_STATE_S1 : ACPI_STATE_UNKNOWN; | ACPI_STATE_S1 : ACPI_STATE_UNKNOWN; | ||||
sc->acpi_suspend_sx = acpi_sleep_states[ACPI_STATE_S3] ? | sc->acpi_suspend.sx = acpi_sleep_states[ACPI_STATE_S3] ? | ||||
ACPI_STATE_S3 : ACPI_STATE_UNKNOWN; | ACPI_STATE_S3 : ACPI_STATE_UNKNOWN; | ||||
/* Pick the first valid sleep state for the sleep button default. */ | /* Pick the first valid sleep state for the sleep button default. */ | ||||
sc->acpi_sleep_button_sx = ACPI_STATE_UNKNOWN; | sc->acpi_sleep_button.sx = ACPI_STATE_UNKNOWN; | ||||
for (state = ACPI_STATE_S1; state <= ACPI_STATE_S4; state++) | for (state = ACPI_STATE_S1; state <= ACPI_STATE_S4; state++) | ||||
if (acpi_sleep_states[state]) { | if (acpi_sleep_states[state]) { | ||||
sc->acpi_sleep_button_sx = state; | sc->acpi_sleep_button.sx = state; | ||||
break; | break; | ||||
} | } | ||||
acpi_enable_fixed_events(sc); | acpi_enable_fixed_events(sc); | ||||
/* | /* | ||||
* Scan the namespace and attach/initialise children. | * Scan the namespace and attach/initialise children. | ||||
*/ | */ | ||||
/* Register our shutdown handler. */ | /* Register our shutdown handler. */ | ||||
EVENTHANDLER_REGISTER(shutdown_final, acpi_shutdown_final, sc, | EVENTHANDLER_REGISTER(shutdown_final, acpi_shutdown_final, sc, | ||||
SHUTDOWN_PRI_LAST); | SHUTDOWN_PRI_LAST); | ||||
/* | /* | ||||
* Register our acpi event handlers. | * Register our acpi event handlers. | ||||
* XXX should be configurable eg. via userland policy manager. | * XXX should be configurable eg. via userland policy manager. | ||||
*/ | */ | ||||
EVENTHANDLER_REGISTER(acpi_sleep_event, acpi_system_eventhandler_sleep, | EVENTHANDLER_REGISTER(acpi_sleep_event, acpi_system_eventhandler_sleep, | ||||
sc, ACPI_EVENT_PRI_LAST); | sc, ACPI_EVENT_PRI_LAST); | ||||
EVENTHANDLER_REGISTER(acpi_wakeup_event, acpi_system_eventhandler_wakeup, | EVENTHANDLER_REGISTER(acpi_wakeup_event, acpi_system_eventhandler_wakeup, | ||||
sc, ACPI_EVENT_PRI_LAST); | sc, ACPI_EVENT_PRI_LAST); | ||||
/* Flag our initial states. */ | /* Flag our initial states. */ | ||||
sc->acpi_enabled = TRUE; | sc->acpi_enabled = TRUE; | ||||
sc->acpi_sstate = ACPI_STATE_S0; | sc->acpi_sstate = AWAKE; | ||||
sc->acpi_sleep_disabled = TRUE; | sc->acpi_repressed_states.flags |= 1 << ACPI_SLEEP_DISABLED; | ||||
/* Create the control device */ | /* Create the control device */ | ||||
sc->acpi_dev_t = make_dev(&acpi_cdevsw, 0, UID_ROOT, GID_OPERATOR, 0664, | sc->acpi_dev_t = make_dev(&acpi_cdevsw, 0, UID_ROOT, GID_OPERATOR, 0664, | ||||
"acpi"); | "acpi"); | ||||
sc->acpi_dev_t->si_drv1 = sc; | sc->acpi_dev_t->si_drv1 = sc; | ||||
if ((error = acpi_machdep_init(dev))) | if ((error = acpi_machdep_init(dev))) | ||||
goto out; | goto out; | ||||
▲ Show 20 Lines • Show All 1,023 Lines • ▼ Show 20 Lines | acpi_device_pwr_for_sleep(device_t bus, device_t dev, int *dstate) | ||||
acpi_MatchHid(handle, "PNP0511")) | acpi_MatchHid(handle, "PNP0511")) | ||||
return (ENXIO); | return (ENXIO); | ||||
/* | /* | ||||
* Override next state with the value from _SxD, if present. | * Override next state with the value from _SxD, if present. | ||||
* Note illegal _S0D is evaluated because some systems expect this. | * Note illegal _S0D is evaluated because some systems expect this. | ||||
*/ | */ | ||||
sc = device_get_softc(bus); | sc = device_get_softc(bus); | ||||
snprintf(sxd, sizeof(sxd), "_S%dD", sc->acpi_sstate); | |||||
snprintf(sxd, sizeof(sxd), "_S%dD", | |||||
sc->acpi_sstate != SUSPEND_TO_IDLE ?: SUSPEND); | |||||
MPASS(sxd[2] < '4'); /* only up to S3 supported */ | |||||
status = acpi_GetInteger(handle, sxd, dstate); | status = acpi_GetInteger(handle, sxd, dstate); | ||||
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { | ||||
device_printf(dev, "failed to get %s on %s: %s\n", sxd, | device_printf(dev, "failed to get %s on %s: %s\n", sxd, | ||||
acpi_name(handle), AcpiFormatException(status)); | acpi_name(handle), AcpiFormatException(status)); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
return (0); | return (0); | ||||
▲ Show 20 Lines • Show All 1,030 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
static int once; | static int once; | ||||
if (!once) { | if (!once) { | ||||
device_printf(sc->acpi_dev, | device_printf(sc->acpi_dev, | ||||
"warning: acpi_SetSleepState() deprecated, need to update your software\n"); | "warning: acpi_SetSleepState() deprecated, need to update your software\n"); | ||||
once = 1; | once = 1; | ||||
} | } | ||||
return (acpi_EnterSleepState(sc, state)); | MPASS(state < ACPI_S_STATES_MAX); | ||||
return (acpi_EnterSleepState(sc, (enum sleep_type) state)); | |||||
} | } | ||||
#if defined(__amd64__) || defined(__i386__) | #if defined(__amd64__) || defined(__i386__) | ||||
static void | static void | ||||
acpi_sleep_force_task(void *context) | acpi_sleep_force_task(void *context) | ||||
{ | { | ||||
struct acpi_softc *sc = (struct acpi_softc *)context; | struct acpi_softc *sc = (struct acpi_softc *)context; | ||||
Show All 12 Lines | "suspend request timed out, forcing sleep now\n"); | ||||
/* | /* | ||||
* XXX Suspending from callout causes freezes in DEVICE_SUSPEND(). | * XXX Suspending from callout causes freezes in DEVICE_SUSPEND(). | ||||
* Suspend from acpi_task thread instead. | * Suspend from acpi_task thread instead. | ||||
*/ | */ | ||||
if (ACPI_FAILURE(AcpiOsExecute(OSL_NOTIFY_HANDLER, | if (ACPI_FAILURE(AcpiOsExecute(OSL_NOTIFY_HANDLER, | ||||
acpi_sleep_force_task, sc))) | acpi_sleep_force_task, sc))) | ||||
device_printf(sc->acpi_dev, "AcpiOsExecute() for sleeping failed\n"); | device_printf(sc->acpi_dev, "AcpiOsExecute() for sleeping failed\n"); | ||||
} | } | ||||
static enum sleep_type | |||||
select_sleep_type(struct acpi_softc *sc, int state) | |||||
{ | |||||
MPASS(state == ACPI_STATE_S3 || state == ACPI_STATE_S1); | |||||
/* The user explicitly requested */ | |||||
if (state == ACPI_STATE_S3 && | |||||
sc->acpi_suspend.sx == SUSPEND_TO_IDLE) | |||||
return SUSPEND_TO_IDLE; | |||||
if (state == ACPI_STATE_S1 && | |||||
sc->acpi_standby.sx == SUSPEND_TO_IDLE) | |||||
return SUSPEND_TO_IDLE; | |||||
/* The system supports the HW state, and that's probably best */ | |||||
if (acpi_sleep_states[state]) | |||||
return (enum sleep_type)state; | |||||
/* idle is the best we can do. */ | |||||
device_printf(sc->acpi_dev, | |||||
"Requested S%d, but using S0IDLE instead\n", state); | |||||
return SUSPEND_TO_IDLE; | |||||
} | |||||
#else | |||||
static enum sleep_type | |||||
select_sleep_type(struct acpi_softc *sc) | |||||
{ | |||||
return AWAKE; | |||||
} | |||||
#endif | #endif | ||||
/* Given a sleep type and a state, figures out if an error is warranted */ | |||||
static int | |||||
sanitize_sstate(struct acpi_softc *sc, enum sleep_type stype, int state, | |||||
bool acpi_err) | |||||
{ | |||||
if (stype == SUSPEND_TO_IDLE) | |||||
goto out; | |||||
if (state < ACPI_STATE_S1 || state > ACPI_S_STATES_MAX) | |||||
return acpi_err ? (AE_BAD_PARAMETER) : (EINVAL); | |||||
if (!acpi_sleep_states[state]) { | |||||
device_printf(sc->acpi_dev, | |||||
"Sleep state S%d not supported by BIOS\n", state); | |||||
return acpi_err ? (AE_SUPPORT) : (EOPNOTSUPP); | |||||
} | |||||
out: | |||||
return acpi_err ? (AE_OK) : (0); | |||||
} | |||||
/* | /* | ||||
* Request that the system enter the given suspend state. All /dev/apm | * Request that the system enter the given suspend state. All /dev/apm | ||||
* devices and devd(8) will be notified. Userland then has a chance to | * devices and devd(8) will be notified. Userland then has a chance to | ||||
* save state and acknowledge the request. The system sleeps once all | * save state and acknowledge the request. The system sleeps once all | ||||
* acks are in. | * acks are in. | ||||
*/ | */ | ||||
int | int | ||||
acpi_ReqSleepState(struct acpi_softc *sc, int state) | acpi_ReqSleepState(struct acpi_softc *sc, enum sleep_type stype) | ||||
{ | { | ||||
#if defined(__amd64__) || defined(__i386__) | #if defined(__amd64__) || defined(__i386__) | ||||
struct apm_clone_data *clone; | struct apm_clone_data *clone; | ||||
ACPI_STATUS status; | ACPI_STATUS status; | ||||
int sstate, err; | |||||
if (state < ACPI_STATE_S1 || state > ACPI_S_STATES_MAX) | sstate = acpi_stype2sstate(stype); | ||||
return (EINVAL); | |||||
if (!acpi_sleep_states[state]) | |||||
return (EOPNOTSUPP); | |||||
err = sanitize_sstate(sc, stype, sstate, false); | |||||
if (err) | |||||
return err; | |||||
/* | /* | ||||
* If a reboot/shutdown/suspend request is already in progress or | * If a reboot/shutdown/suspend request is already in progress or | ||||
* suspend is blocked due to an upcoming shutdown, just return. | * suspend is blocked due to an upcoming shutdown, just return. | ||||
*/ | */ | ||||
if (rebooting || sc->acpi_next_sstate != 0 || suspend_blocked) { | if (rebooting || sc->acpi_next_sstate != AWAKE || suspend_blocked) { | ||||
return (0); | return (0); | ||||
} | } | ||||
/* Wait until sleep is enabled. */ | /* Wait until sleep is enabled. */ | ||||
while (sc->acpi_sleep_disabled) { | while (sc->acpi_repressed_states.flags & (1 <<ACPI_SLEEP_DISABLED)) { | ||||
AcpiOsSleep(1000); | AcpiOsSleep(1000); | ||||
} | } | ||||
ACPI_LOCK(acpi); | ACPI_LOCK(acpi); | ||||
sc->acpi_next_sstate = state; | sc->acpi_next_sstate = stype; | ||||
/* S5 (soft-off) should be entered directly with no waiting. */ | /* S5 (soft-off) should be entered directly with no waiting. */ | ||||
if (state == ACPI_STATE_S5) { | if (stype == POWEROFF) { | ||||
ACPI_UNLOCK(acpi); | ACPI_UNLOCK(acpi); | ||||
status = acpi_EnterSleepState(sc, state); | status = acpi_EnterSleepState(sc, stype); | ||||
return (ACPI_SUCCESS(status) ? 0 : ENXIO); | return (ACPI_SUCCESS(status) ? 0 : ENXIO); | ||||
} | } | ||||
/* Record the pending state and notify all apm devices. */ | /* Record the pending state and notify all apm devices. */ | ||||
STAILQ_FOREACH(clone, &sc->apm_cdevs, entries) { | STAILQ_FOREACH(clone, &sc->apm_cdevs, entries) { | ||||
clone->notify_status = APM_EV_NONE; | clone->notify_status = APM_EV_NONE; | ||||
if ((clone->flags & ACPI_EVF_DEVD) == 0) { | if ((clone->flags & ACPI_EVF_DEVD) == 0) { | ||||
selwakeuppri(&clone->sel_read, PZERO); | selwakeuppri(&clone->sel_read, PZERO); | ||||
KNOTE_LOCKED(&clone->sel_read.si_note, 0); | KNOTE_LOCKED(&clone->sel_read.si_note, 0); | ||||
} | } | ||||
} | } | ||||
/* If devd(8) is not running, immediately enter the sleep state. */ | /* If devd(8) is not running, immediately enter the sleep state. */ | ||||
if (!devctl_process_running()) { | if (!devctl_process_running()) { | ||||
ACPI_UNLOCK(acpi); | ACPI_UNLOCK(acpi); | ||||
status = acpi_EnterSleepState(sc, state); | status = acpi_EnterSleepState(sc, stype); | ||||
return (ACPI_SUCCESS(status) ? 0 : ENXIO); | return (ACPI_SUCCESS(status) ? 0 : ENXIO); | ||||
} | } | ||||
/* | /* | ||||
* Set a timeout to fire if userland doesn't ack the suspend request | * Set a timeout to fire if userland doesn't ack the suspend request | ||||
* in time. This way we still eventually go to sleep if we were | * in time. This way we still eventually go to sleep if we were | ||||
* overheating or running low on battery, even if userland is hung. | * overheating or running low on battery, even if userland is hung. | ||||
* We cancel this timeout once all userland acks are in or the | * We cancel this timeout once all userland acks are in or the | ||||
* suspend request is aborted. | * suspend request is aborted. | ||||
*/ | */ | ||||
callout_reset(&sc->susp_force_to, 10 * hz, acpi_sleep_force, sc); | callout_reset(&sc->susp_force_to, 10 * hz, acpi_sleep_force, sc); | ||||
ACPI_UNLOCK(acpi); | ACPI_UNLOCK(acpi); | ||||
/* Now notify devd(8) also. */ | /* Now notify devd(8) also. */ | ||||
acpi_UserNotify("Suspend", ACPI_ROOT_OBJECT, state); | acpi_UserNotify("Suspend", ACPI_ROOT_OBJECT, stype); | ||||
return (0); | return (0); | ||||
#else | #else | ||||
/* This platform does not support acpi suspend/resume. */ | /* | ||||
* This platform does not support acpi suspend/resume. | |||||
* TODO: Support s2idle here since it's platform agnostic. | |||||
*/ | |||||
imp: Would it be appropriate to have a printf here? I'm on the fence about this. | |||||
return (EOPNOTSUPP); | return (EOPNOTSUPP); | ||||
#endif | #endif | ||||
} | } | ||||
/* | /* | ||||
* Acknowledge (or reject) a pending sleep state. The caller has | * Acknowledge (or reject) a pending sleep state. The caller has | ||||
* prepared for suspend and is now ready for it to proceed. If the | * prepared for suspend and is now ready for it to proceed. If the | ||||
* error argument is non-zero, it indicates suspend should be cancelled | * error argument is non-zero, it indicates suspend should be cancelled | ||||
* and gives an errno value describing why. Once all votes are in, | * and gives an errno value describing why. Once all votes are in, | ||||
* we suspend the system. | * we suspend the system. | ||||
*/ | */ | ||||
int | int | ||||
acpi_AckSleepState(struct apm_clone_data *clone, int error) | acpi_AckSleepState(struct apm_clone_data *clone, int error) | ||||
{ | { | ||||
#if defined(__amd64__) || defined(__i386__) | #if defined(__amd64__) || defined(__i386__) | ||||
struct acpi_softc *sc; | struct acpi_softc *sc; | ||||
int ret, sleeping; | int ret, sleeping; | ||||
/* If no pending sleep state, return an error. */ | /* If no pending sleep state, return an error. */ | ||||
ACPI_LOCK(acpi); | ACPI_LOCK(acpi); | ||||
sc = clone->acpi_sc; | sc = clone->acpi_sc; | ||||
if (sc->acpi_next_sstate == 0) { | if (sc->acpi_next_sstate == AWAKE) { | ||||
ACPI_UNLOCK(acpi); | ACPI_UNLOCK(acpi); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
/* Caller wants to abort suspend process. */ | /* Caller wants to abort suspend process. */ | ||||
if (error) { | if (error) { | ||||
sc->acpi_next_sstate = 0; | sc->acpi_next_sstate = AWAKE; | ||||
callout_stop(&sc->susp_force_to); | callout_stop(&sc->susp_force_to); | ||||
device_printf(sc->acpi_dev, | device_printf(sc->acpi_dev, | ||||
"listener on %s cancelled the pending suspend\n", | "listener on %s cancelled the pending suspend\n", | ||||
devtoname(clone->cdev)); | devtoname(clone->cdev)); | ||||
ACPI_UNLOCK(acpi); | ACPI_UNLOCK(acpi); | ||||
return (0); | return (0); | ||||
} | } | ||||
Show All 18 Lines | callout_stop(&sc->susp_force_to); | ||||
ACPI_UNLOCK(acpi); | ACPI_UNLOCK(acpi); | ||||
ret = 0; | ret = 0; | ||||
if (sleeping) { | if (sleeping) { | ||||
if (ACPI_FAILURE(acpi_EnterSleepState(sc, sc->acpi_next_sstate))) | if (ACPI_FAILURE(acpi_EnterSleepState(sc, sc->acpi_next_sstate))) | ||||
ret = ENODEV; | ret = ENODEV; | ||||
} | } | ||||
return (ret); | return (ret); | ||||
#else | #else | ||||
/* This platform does not support acpi suspend/resume. */ | /* | ||||
* This platform does not support acpi suspend/resume. | |||||
* TODO: Support s2idle here since it's platform agnostic. | |||||
*/ | |||||
impUnsubmitted Not Done Inline ActionsSame comment as above. imp: Same comment as above. | |||||
return (EOPNOTSUPP); | return (EOPNOTSUPP); | ||||
#endif | #endif | ||||
} | } | ||||
static void | static void | ||||
acpi_sleep_enable(void *arg) | acpi_sleep_enable(void *arg) | ||||
{ | { | ||||
struct acpi_softc *sc = (struct acpi_softc *)arg; | struct acpi_softc *sc = (struct acpi_softc *)arg; | ||||
ACPI_LOCK_ASSERT(acpi); | ACPI_LOCK_ASSERT(acpi); | ||||
/* Reschedule if the system is not fully up and running. */ | /* Reschedule if the system is not fully up and running. */ | ||||
if (!AcpiGbl_SystemAwakeAndRunning) { | if (!AcpiGbl_SystemAwakeAndRunning) { | ||||
callout_schedule(&acpi_sleep_timer, hz * ACPI_MINIMUM_AWAKETIME); | callout_schedule(&acpi_sleep_timer, hz * ACPI_MINIMUM_AWAKETIME); | ||||
return; | return; | ||||
} | } | ||||
sc->acpi_sleep_disabled = FALSE; | atomic_clear_int(&sc->acpi_repressed_states.flags, 1 << ACPI_SLEEP_DISABLED); | ||||
} | } | ||||
static ACPI_STATUS | static ACPI_STATUS | ||||
acpi_sleep_disable(struct acpi_softc *sc) | acpi_sleep_disable(struct acpi_softc *sc) | ||||
{ | { | ||||
ACPI_STATUS status; | |||||
/* Fail if the system is not fully up and running. */ | /* Fail if the system is not fully up and running. */ | ||||
if (!AcpiGbl_SystemAwakeAndRunning) | if (!AcpiGbl_SystemAwakeAndRunning) | ||||
return (AE_ERROR); | return (AE_ERROR); | ||||
ACPI_LOCK(acpi); | if (atomic_testandset_int(&sc->acpi_repressed_states.flags, ACPI_SLEEP_DISABLED)) | ||||
status = sc->acpi_sleep_disabled ? AE_ERROR : AE_OK; | return AE_ERROR; | ||||
sc->acpi_sleep_disabled = TRUE; | |||||
ACPI_UNLOCK(acpi); | |||||
return (status); | return AE_OK; | ||||
} | } | ||||
enum acpi_sleep_state { | enum acpi_sleep_state { | ||||
ACPI_SS_NONE, | ACPI_SS_NONE, | ||||
ACPI_SS_GPE_SET, | ACPI_SS_GPE_SET, | ||||
ACPI_SS_DEV_SUSPEND, | ACPI_SS_DEV_SUSPEND, | ||||
ACPI_SS_SLP_PREP, | ACPI_SS_SLP_PREP, | ||||
ACPI_SS_SLEPT, | ACPI_SS_SLEPT, | ||||
}; | }; | ||||
static void | |||||
acpi_state_transition_disable(struct acpi_softc *sc) | |||||
{ | |||||
int tmp; | |||||
tmp = atomic_swap_int(&sc->acpi_repressed_states.flags, ~0); | |||||
/* Disallow re-entrancy. Disabling sleep with this is allowed though. */ | |||||
if (tmp & ~(1 << ACPI_SLEEP_DISABLED)) { | |||||
device_printf(sc->acpi_dev, "Invalid saved power flags"); | |||||
tmp &= (1 << ACPI_SLEEP_DISABLED); | |||||
} | |||||
sc->acpi_repressed_states.saved_flags = tmp; | |||||
} | |||||
static void | |||||
acpi_state_transition_enable(struct acpi_softc *sc) | |||||
{ | |||||
#ifdef INVARIANTS | |||||
int tmp; | |||||
tmp = atomic_swap_int(&sc->acpi_repressed_states.flags, sc->acpi_repressed_states.saved_flags); | |||||
MPASS(tmp == ~0); | |||||
#else | |||||
atomic_store_int(&sc->acpi_repressed_states.flags, sc->sc->acpi_repressed_states.saved_flags); | |||||
#endif | |||||
sc->acpi_repressed_states.saved_flags = 0; | |||||
} | |||||
BOOLEAN | |||||
acpi_PowerTransitionIsEnabled() | |||||
{ | |||||
struct acpi_softc *sc = devclass_get_softc(devclass_find("acpi"), 0); | |||||
MPASS(sc != NULL); | |||||
return (sc->acpi_repressed_states.flags & (1 << ACPI_POWER_DISABLED)) == 0; | |||||
} | |||||
static void | |||||
__do_idle(struct acpi_softc *sc) | |||||
{ | |||||
register_t intr; | |||||
intr = intr_disable(); | |||||
intr_suspend(); | |||||
/* XXX: Is this actually required? */ | |||||
intr_enable_src(acpi_GetSciInterrupt()); | |||||
acpi_state_transition_disable(sc); | |||||
cpu_idle(0); | |||||
acpi_state_transition_enable(sc); | |||||
intr_resume(false); | |||||
intr_restore(intr); | |||||
} | |||||
static void | |||||
__do_sleep(struct acpi_softc *sc, int state, enum acpi_sleep_state *pass) | |||||
{ | |||||
int sleep_result; | |||||
register_t intr; | |||||
MPASS(state == ACPI_STATE_S3 || state == ACPI_STATE_S4); | |||||
intr = intr_disable(); | |||||
sleep_result = acpi_sleep_machdep(sc, state); | |||||
acpi_wakeup_machdep(sc, state, sleep_result, 0); | |||||
if (sleep_result == 1 && state == ACPI_STATE_S3) { | |||||
/* | /* | ||||
* XXX According to ACPI specification SCI_EN bit should be restored by | |||||
* ACPI platform (BIOS, firmware) to its pre-sleep state. Unfortunately | |||||
* some BIOSes fail to do that and that leads to unexpected and serious | |||||
* consequences during wake up like a system getting stuck in SMI | |||||
* handlers. This hack is picked up from Linux, which claims that it | |||||
* follows Windows behavior. | |||||
*/ | |||||
AcpiWriteBitRegister(ACPI_BITREG_SCI_ENABLE, ACPI_ENABLE_EVENT); | |||||
} | |||||
intr_restore(intr); | |||||
/* call acpi_wakeup_machdep() again with interrupt enabled */ | |||||
acpi_wakeup_machdep(sc, state, sleep_result, 1); | |||||
AcpiLeaveSleepStatePrep(state); | |||||
if (sleep_result == -1) | |||||
return; | |||||
/* Re-enable ACPI hardware on wakeup from sleep state 4. */ | |||||
if (state == ACPI_STATE_S4) | |||||
AcpiEnable(); | |||||
*pass = ACPI_SS_SLEPT; | |||||
} | |||||
/* | |||||
* Enter the desired system sleep state. | * Enter the desired system sleep state. | ||||
* | * | ||||
* Currently we support S1-S5 but S4 is only S4BIOS | * Currently we support S1-S5 but S4 is only S4BIOS | ||||
*/ | */ | ||||
static ACPI_STATUS | static ACPI_STATUS | ||||
acpi_EnterSleepState(struct acpi_softc *sc, int state) | acpi_EnterSleepState(struct acpi_softc *sc, enum sleep_type stype) | ||||
{ | { | ||||
register_t intr; | |||||
ACPI_STATUS status; | ACPI_STATUS status; | ||||
ACPI_EVENT_STATUS power_button_status; | |||||
enum acpi_sleep_state slp_state; | enum acpi_sleep_state slp_state; | ||||
int sleep_result; | int state, err; | ||||
ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state); | ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, stype); | ||||
if (state < ACPI_STATE_S1 || state > ACPI_S_STATES_MAX) | state = acpi_stype2sstate(stype); | ||||
return_ACPI_STATUS (AE_BAD_PARAMETER); | |||||
if (!acpi_sleep_states[state]) { | |||||
device_printf(sc->acpi_dev, "Sleep state S%d not supported by BIOS\n", | |||||
state); | |||||
return (AE_SUPPORT); | |||||
} | |||||
err = sanitize_sstate(sc, stype, state, true); | |||||
if (err) | |||||
return_ACPI_STATUS (err); | |||||
/* Re-entry once we're suspending is not allowed. */ | /* Re-entry once we're suspending is not allowed. */ | ||||
status = acpi_sleep_disable(sc); | status = acpi_sleep_disable(sc); | ||||
if (ACPI_FAILURE(status)) { | if (ACPI_FAILURE(status)) { | ||||
device_printf(sc->acpi_dev, | device_printf(sc->acpi_dev, | ||||
"suspend request ignored (not ready yet)\n"); | "suspend request ignored (not ready yet)\n"); | ||||
return (status); | return (status); | ||||
} | } | ||||
if (state == ACPI_STATE_S5) { | if (stype == POWEROFF) { | ||||
/* | /* | ||||
* Shut down cleanly and power off. This will call us back through the | * Shut down cleanly and power off. This will call us back through the | ||||
* shutdown handlers. | * shutdown handlers. | ||||
*/ | */ | ||||
shutdown_nice(RB_POWEROFF); | shutdown_nice(RB_POWEROFF); | ||||
return_ACPI_STATUS (AE_OK); | return_ACPI_STATUS (AE_OK); | ||||
} | } | ||||
EVENTHANDLER_INVOKE(power_suspend_early); | EVENTHANDLER_INVOKE(power_suspend_early); | ||||
stop_all_proc(); | stop_all_proc(); | ||||
EVENTHANDLER_INVOKE(power_suspend); | EVENTHANDLER_INVOKE(power_suspend); | ||||
#ifdef EARLY_AP_STARTUP | |||||
MPASS(mp_ncpus == 1 || smp_started); | MPASS(mp_ncpus == 1 || smp_started); | ||||
thread_lock(curthread); | |||||
sched_bind(curthread, 0); | |||||
thread_unlock(curthread); | |||||
#else | |||||
if (smp_started) { | if (smp_started) { | ||||
thread_lock(curthread); | thread_lock(curthread); | ||||
sched_bind(curthread, 0); | sched_bind(curthread, 0); | ||||
thread_unlock(curthread); | thread_unlock(curthread); | ||||
} | } | ||||
#endif | |||||
/* | /* | ||||
* Be sure to hold Giant across DEVICE_SUSPEND/RESUME since non-MPSAFE | * Be sure to hold Giant across DEVICE_SUSPEND/RESUME since non-MPSAFE | ||||
* drivers need this. | * drivers need this. | ||||
*/ | */ | ||||
mtx_lock(&Giant); | mtx_lock(&Giant); | ||||
slp_state = ACPI_SS_NONE; | slp_state = ACPI_SS_NONE; | ||||
sc->acpi_sstate = state; | sc->acpi_sstate = stype; | ||||
/* Enable any GPEs as appropriate and requested by the user. */ | /* Enable any GPEs as appropriate and requested by the user. */ | ||||
acpi_wake_prep_walk(state); | acpi_wake_prep_walk(state); | ||||
slp_state = ACPI_SS_GPE_SET; | slp_state = ACPI_SS_GPE_SET; | ||||
/* | /* | ||||
* Inform all devices that we are going to sleep. If at least one | * Inform all devices that we are going to sleep. If at least one | ||||
* device fails, DEVICE_SUSPEND() automatically resumes the tree. | * device fails, DEVICE_SUSPEND() automatically resumes the tree. | ||||
* | * | ||||
* XXX Note that a better two-pass approach with a 'veto' pass | * XXX Note that a better two-pass approach with a 'veto' pass | ||||
* followed by a "real thing" pass would be better, but the current | * followed by a "real thing" pass would be better, but the current | ||||
* bus interface does not provide for this. | * bus interface does not provide for this. | ||||
*/ | */ | ||||
if (DEVICE_SUSPEND(root_bus) != 0) { | if (DEVICE_SUSPEND(root_bus) != 0) { | ||||
device_printf(sc->acpi_dev, "device_suspend failed\n"); | device_printf(sc->acpi_dev, "device_suspend failed\n"); | ||||
goto backout; | goto backout; | ||||
} | } | ||||
slp_state = ACPI_SS_DEV_SUSPEND; | slp_state = ACPI_SS_DEV_SUSPEND; | ||||
if (stype != SUSPEND_TO_IDLE) { | |||||
status = AcpiEnterSleepStatePrep(state); | status = AcpiEnterSleepStatePrep(state); | ||||
if (ACPI_FAILURE(status)) { | if (ACPI_FAILURE(status)) { | ||||
device_printf(sc->acpi_dev, "AcpiEnterSleepStatePrep failed - %s\n", | device_printf(sc->acpi_dev, "AcpiEnterSleepStatePrep failed - %s\n", | ||||
AcpiFormatException(status)); | AcpiFormatException(status)); | ||||
goto backout; | goto backout; | ||||
} | } | ||||
} | |||||
slp_state = ACPI_SS_SLP_PREP; | slp_state = ACPI_SS_SLP_PREP; | ||||
if (sc->acpi_sleep_delay > 0) | if (sc->acpi_sleep_delay > 0) | ||||
DELAY(sc->acpi_sleep_delay * 1000000); | DELAY(sc->acpi_sleep_delay * 1000000); | ||||
suspendclock(); | suspendclock(); | ||||
intr = intr_disable(); | switch (stype) { | ||||
if (state != ACPI_STATE_S1) { | case STANDBY: | ||||
sleep_result = acpi_sleep_machdep(sc, state); | { | ||||
acpi_wakeup_machdep(sc, state, sleep_result, 0); | register_t intr = intr_disable(); | ||||
/* | |||||
* XXX According to ACPI specification SCI_EN bit should be restored | |||||
* by ACPI platform (BIOS, firmware) to its pre-sleep state. | |||||
* Unfortunately some BIOSes fail to do that and that leads to | |||||
* unexpected and serious consequences during wake up like a system | |||||
* getting stuck in SMI handlers. | |||||
* This hack is picked up from Linux, which claims that it follows | |||||
* Windows behavior. | |||||
*/ | |||||
if (sleep_result == 1 && state != ACPI_STATE_S4) | |||||
AcpiWriteBitRegister(ACPI_BITREG_SCI_ENABLE, ACPI_ENABLE_EVENT); | |||||
if (sleep_result == 1 && state == ACPI_STATE_S3) { | |||||
/* | |||||
* Prevent mis-interpretation of the wakeup by power button | |||||
* as a request for power off. | |||||
* Ideally we should post an appropriate wakeup event, | |||||
* perhaps using acpi_event_power_button_wake or alike. | |||||
* | |||||
* Clearing of power button status after wakeup is mandated | |||||
* by ACPI specification in section "Fixed Power Button". | |||||
* | |||||
* XXX As of ACPICA 20121114 AcpiGetEventStatus provides | |||||
* status as 0/1 corressponding to inactive/active despite | |||||
* its type being ACPI_EVENT_STATUS. In other words, | |||||
* we should not test for ACPI_EVENT_FLAG_SET for time being. | |||||
*/ | |||||
if (ACPI_SUCCESS(AcpiGetEventStatus(ACPI_EVENT_POWER_BUTTON, | |||||
&power_button_status)) && power_button_status != 0) { | |||||
AcpiClearEvent(ACPI_EVENT_POWER_BUTTON); | |||||
device_printf(sc->acpi_dev, | |||||
"cleared fixed power button status\n"); | |||||
} | |||||
} | |||||
intr_restore(intr); | |||||
/* call acpi_wakeup_machdep() again with interrupt enabled */ | |||||
acpi_wakeup_machdep(sc, state, sleep_result, 1); | |||||
AcpiLeaveSleepStatePrep(state); | |||||
if (sleep_result == -1) | |||||
goto backout; | |||||
/* Re-enable ACPI hardware on wakeup from sleep state 4. */ | |||||
if (state == ACPI_STATE_S4) | |||||
AcpiEnable(); | |||||
} else { | |||||
status = AcpiEnterSleepState(state); | status = AcpiEnterSleepState(state); | ||||
intr_restore(intr); | intr_restore(intr); | ||||
AcpiLeaveSleepStatePrep(state); | AcpiLeaveSleepStatePrep(state); | ||||
if (ACPI_FAILURE(status)) { | if (ACPI_FAILURE(status)) | ||||
device_printf(sc->acpi_dev, "AcpiEnterSleepState failed - %s\n", | device_printf(sc->acpi_dev, "AcpiEnterSleepState failed - %s\n", | ||||
AcpiFormatException(status)); | AcpiFormatException(status)); | ||||
goto backout; | slp_state = ACPI_SS_SLEPT; | ||||
} | } | ||||
break; | |||||
case SUSPEND: | |||||
case HIBERNATE: | |||||
__do_sleep(sc, state, &slp_state); | |||||
break; | |||||
case SUSPEND_TO_IDLE: | |||||
__do_idle(sc); | |||||
break; | |||||
case AWAKE: | |||||
case POWEROFF: | |||||
default: | |||||
__unreachable(); | |||||
} | } | ||||
slp_state = ACPI_SS_SLEPT; | |||||
/* | /* | ||||
* Back out state according to how far along we got in the suspend | * Back out state according to how far along we got in the suspend | ||||
* process. This handles both the error and success cases. | * process. This handles both the error and success cases. | ||||
*/ | */ | ||||
backout: | backout: | ||||
if (slp_state >= ACPI_SS_SLP_PREP) | if (slp_state >= ACPI_SS_SLP_PREP) | ||||
resumeclock(); | resumeclock(); | ||||
if (slp_state >= ACPI_SS_GPE_SET) { | if (slp_state >= ACPI_SS_GPE_SET) { | ||||
acpi_wake_prep_walk(state); | acpi_wake_prep_walk(state); | ||||
sc->acpi_sstate = ACPI_STATE_S0; | sc->acpi_sstate = AWAKE; | ||||
} | } | ||||
if (slp_state >= ACPI_SS_DEV_SUSPEND) | if (slp_state >= ACPI_SS_DEV_SUSPEND) | ||||
DEVICE_RESUME(root_bus); | DEVICE_RESUME(root_bus); | ||||
if (slp_state >= ACPI_SS_SLP_PREP) | |||||
if (stype != SUSPEND_TO_IDLE && (slp_state >= ACPI_SS_SLP_PREP)) | |||||
AcpiLeaveSleepState(state); | AcpiLeaveSleepState(state); | ||||
if (slp_state >= ACPI_SS_SLEPT) { | if (slp_state >= ACPI_SS_SLEPT) { | ||||
#if defined(__i386__) || defined(__amd64__) | #if defined(__i386__) || defined(__amd64__) | ||||
/* NB: we are still using ACPI timecounter at this point. */ | /* NB: we are still using ACPI timecounter at this point. */ | ||||
resume_TSC(); | resume_TSC(); | ||||
#endif | #endif | ||||
acpi_resync_clock(sc); | acpi_resync_clock(sc); | ||||
acpi_enable_fixed_events(sc); | acpi_enable_fixed_events(sc); | ||||
} | } | ||||
sc->acpi_next_sstate = 0; | sc->acpi_next_sstate = AWAKE; | ||||
mtx_unlock(&Giant); | mtx_unlock(&Giant); | ||||
#ifdef EARLY_AP_STARTUP | |||||
thread_lock(curthread); | |||||
sched_unbind(curthread); | |||||
thread_unlock(curthread); | |||||
#else | |||||
if (smp_started) { | if (smp_started) { | ||||
thread_lock(curthread); | thread_lock(curthread); | ||||
sched_unbind(curthread); | sched_unbind(curthread); | ||||
thread_unlock(curthread); | thread_unlock(curthread); | ||||
} | } | ||||
#endif | |||||
resume_all_proc(); | resume_all_proc(); | ||||
EVENTHANDLER_INVOKE(power_resume); | EVENTHANDLER_INVOKE(power_resume); | ||||
/* Allow another sleep request after a while. */ | /* Allow another sleep request after a while. */ | ||||
callout_schedule(&acpi_sleep_timer, hz * ACPI_MINIMUM_AWAKETIME); | callout_schedule(&acpi_sleep_timer, hz * ACPI_MINIMUM_AWAKETIME); | ||||
▲ Show 20 Lines • Show All 296 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* ACPI Event Handlers | * ACPI Event Handlers | ||||
*/ | */ | ||||
/* System Event Handlers (registered by EVENTHANDLER_REGISTER) */ | /* System Event Handlers (registered by EVENTHANDLER_REGISTER) */ | ||||
static void | static void | ||||
acpi_system_eventhandler_sleep(void *arg, int state) | acpi_system_eventhandler_sleep(void *arg, enum sleep_type type) | ||||
{ | { | ||||
struct acpi_softc *sc = (struct acpi_softc *)arg; | struct acpi_softc *sc = (struct acpi_softc *)arg; | ||||
int ret; | int ret; | ||||
ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state); | ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, type); | ||||
/* Check if button action is disabled or unknown. */ | /* Check if button action is disabled or unknown. */ | ||||
if (state == ACPI_STATE_UNKNOWN) | if (type > SUSPEND_TO_IDLE) | ||||
return; | return; | ||||
if (!acpi_PowerTransitionIsEnabled()) | |||||
return; | |||||
/* Request that the system prepare to enter the given suspend state. */ | /* Request that the system prepare to enter the given suspend state. */ | ||||
ret = acpi_ReqSleepState(sc, state); | ret = acpi_ReqSleepState(sc, type); | ||||
if (ret != 0) | if (ret != 0) { | ||||
char state[2] = { 0 }; | |||||
state[0] = type + '0'; | |||||
device_printf(sc->acpi_dev, | device_printf(sc->acpi_dev, | ||||
"request to enter state S%d failed (err %d)\n", state, ret); | "request to enter state S%s failed (err %d)\n", | ||||
type == SUSPEND_TO_IDLE ? "0IDLE" : state, | |||||
ret); | |||||
} | |||||
return_VOID; | return_VOID; | ||||
} | } | ||||
static void | static void | ||||
acpi_system_eventhandler_wakeup(void *arg, int state) | acpi_system_eventhandler_wakeup(void *arg, enum sleep_type type) | ||||
{ | { | ||||
ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state); | ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, type); | ||||
/* Currently, nothing to do for wakeup. */ | /* Currently, nothing to do for wakeup. */ | ||||
MPASS(acpi_PowerTransitionIsEnabled()); | |||||
return_VOID; | return_VOID; | ||||
} | } | ||||
/* | /* | ||||
* ACPICA Event Handlers (FixedEvent, also called from button notify handler) | * ACPICA Event Handlers (FixedEvent, also called from button notify handler) | ||||
*/ | */ | ||||
static void | static void | ||||
Show All 13 Lines | |||||
UINT32 | UINT32 | ||||
acpi_event_power_button_sleep(void *context) | acpi_event_power_button_sleep(void *context) | ||||
{ | { | ||||
struct acpi_softc *sc = (struct acpi_softc *)context; | struct acpi_softc *sc = (struct acpi_softc *)context; | ||||
ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); | ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); | ||||
if (ACPI_FAILURE(AcpiOsExecute(OSL_NOTIFY_HANDLER, | if (ACPI_FAILURE(AcpiOsExecute(OSL_NOTIFY_HANDLER, | ||||
acpi_invoke_sleep_eventhandler, &sc->acpi_power_button_sx))) | acpi_invoke_sleep_eventhandler, &sc->acpi_power_button.sx))) | ||||
return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); | return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); | ||||
return_VALUE (ACPI_INTERRUPT_HANDLED); | return_VALUE (ACPI_INTERRUPT_HANDLED); | ||||
} | } | ||||
UINT32 | UINT32 | ||||
acpi_event_power_button_wake(void *context) | acpi_event_power_button_wake(void *context) | ||||
{ | { | ||||
ACPI_STATUS status; | |||||
ACPI_EVENT_STATUS power_button_status; | |||||
struct acpi_softc *sc = (struct acpi_softc *)context; | struct acpi_softc *sc = (struct acpi_softc *)context; | ||||
ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); | ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); | ||||
if (ACPI_FAILURE(AcpiOsExecute(OSL_NOTIFY_HANDLER, | status = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_invoke_wake_eventhandler, | ||||
acpi_invoke_wake_eventhandler, &sc->acpi_power_button_sx))) | &sc->acpi_power_button.sx); | ||||
if (ACPI_FAILURE(status)) | |||||
return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); | return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); | ||||
status = AcpiGetEventStatus(ACPI_EVENT_POWER_BUTTON, &power_button_status); | |||||
if (ACPI_SUCCESS(status) && power_button_status != 0) { | |||||
AcpiClearEvent(ACPI_EVENT_POWER_BUTTON); | |||||
device_printf(sc->acpi_dev, "cleared fixed power button status\n"); | |||||
} | |||||
return_VALUE (ACPI_INTERRUPT_HANDLED); | return_VALUE (ACPI_INTERRUPT_HANDLED); | ||||
} | } | ||||
UINT32 | UINT32 | ||||
acpi_event_sleep_button_sleep(void *context) | acpi_event_sleep_button_sleep(void *context) | ||||
{ | { | ||||
struct acpi_softc *sc = (struct acpi_softc *)context; | struct acpi_softc *sc = (struct acpi_softc *)context; | ||||
ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); | ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); | ||||
if (ACPI_FAILURE(AcpiOsExecute(OSL_NOTIFY_HANDLER, | if (ACPI_FAILURE(AcpiOsExecute(OSL_NOTIFY_HANDLER, | ||||
acpi_invoke_sleep_eventhandler, &sc->acpi_sleep_button_sx))) | acpi_invoke_sleep_eventhandler, &sc->acpi_sleep_button.sx))) | ||||
return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); | return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); | ||||
return_VALUE (ACPI_INTERRUPT_HANDLED); | return_VALUE (ACPI_INTERRUPT_HANDLED); | ||||
} | } | ||||
UINT32 | UINT32 | ||||
acpi_event_sleep_button_wake(void *context) | acpi_event_sleep_button_wake(void *context) | ||||
{ | { | ||||
struct acpi_softc *sc = (struct acpi_softc *)context; | struct acpi_softc *sc = (struct acpi_softc *)context; | ||||
ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); | ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); | ||||
if (ACPI_FAILURE(AcpiOsExecute(OSL_NOTIFY_HANDLER, | if (ACPI_FAILURE(AcpiOsExecute(OSL_NOTIFY_HANDLER, | ||||
acpi_invoke_wake_eventhandler, &sc->acpi_sleep_button_sx))) | acpi_invoke_wake_eventhandler, &sc->acpi_sleep_button.sx))) | ||||
return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); | return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); | ||||
return_VALUE (ACPI_INTERRUPT_HANDLED); | return_VALUE (ACPI_INTERRUPT_HANDLED); | ||||
} | } | ||||
/* | /* | ||||
* XXX This static buffer is suboptimal. There is no locking so only | * XXX This static buffer is suboptimal. There is no locking so only | ||||
* use this for single-threaded callers. | * use this for single-threaded callers. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 211 Lines • ▼ Show 20 Lines | return (hp->fn(cmd, addr, hp->arg)); | ||||
if ((flag & FWRITE) == 0) | if ((flag & FWRITE) == 0) | ||||
return (EPERM); | return (EPERM); | ||||
/* Core system ioctls. */ | /* Core system ioctls. */ | ||||
switch (cmd) { | switch (cmd) { | ||||
case ACPIIO_REQSLPSTATE: | case ACPIIO_REQSLPSTATE: | ||||
state = *(int *)addr; | state = *(int *)addr; | ||||
if (state != ACPI_STATE_S5) | if (state != ACPI_STATE_S5) | ||||
return (acpi_ReqSleepState(sc, state)); | return (acpi_ReqSleepState(sc, select_sleep_type(sc, state))); | ||||
device_printf(sc->acpi_dev, "power off via acpi ioctl not supported\n"); | device_printf(sc->acpi_dev, "power off via acpi ioctl not supported\n"); | ||||
error = EOPNOTSUPP; | error = EOPNOTSUPP; | ||||
break; | break; | ||||
case ACPIIO_ACKSLPSTATE: | case ACPIIO_ACKSLPSTATE: | ||||
error = *(int *)addr; | error = *(int *)addr; | ||||
error = acpi_AckSleepState(sc->acpi_clone, error); | error = acpi_AckSleepState(sc->acpi_clone, error); | ||||
break; | break; | ||||
case ACPIIO_SETSLPSTATE: /* DEPRECATED */ | case ACPIIO_SETSLPSTATE: /* DEPRECATED */ | ||||
state = *(int *)addr; | state = *(int *)addr; | ||||
if (state < ACPI_STATE_S0 || state > ACPI_S_STATES_MAX) | if (state < ACPI_STATE_S0 || state > ACPI_S_STATES_MAX) | ||||
return (EINVAL); | return (EINVAL); | ||||
if (!acpi_sleep_states[state]) | if (!acpi_sleep_states[state]) | ||||
return (EOPNOTSUPP); | return (EOPNOTSUPP); | ||||
if (ACPI_FAILURE(acpi_SetSleepState(sc, state))) | if (ACPI_FAILURE(acpi_SetSleepState(sc, (enum sleep_type) state))) | ||||
error = ENXIO; | error = ENXIO; | ||||
break; | break; | ||||
default: | default: | ||||
error = ENXIO; | error = ENXIO; | ||||
break; | break; | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
acpi_stype2sstate(enum sleep_type type) | |||||
{ | |||||
if (type == SUSPEND_TO_IDLE) | |||||
return ACPI_STATE_UNKNOWN; | |||||
return (int)type; | |||||
} | |||||
static int | |||||
acpi_sname2sstate(const char *sname) | acpi_sname2sstate(const char *sname) | ||||
{ | { | ||||
int sstate; | int sstate; | ||||
if (toupper(sname[0]) == 'S') { | if (toupper(sname[0]) == 'S') { | ||||
sstate = sname[1] - '0'; | sstate = sname[1] - '0'; | ||||
if (sstate >= ACPI_STATE_S0 && sstate <= ACPI_STATE_S5 && | if (sstate >= ACPI_STATE_S0 && sstate <= ACPI_STATE_S5 && | ||||
sname[2] == '\0') | sname[2] == '\0') | ||||
Show All 21 Lines | acpi_supported_sleep_state_sysctl(SYSCTL_HANDLER_ARGS) | ||||
int error; | int error; | ||||
struct sbuf sb; | struct sbuf sb; | ||||
UINT8 state; | UINT8 state; | ||||
sbuf_new(&sb, NULL, 32, SBUF_AUTOEXTEND); | sbuf_new(&sb, NULL, 32, SBUF_AUTOEXTEND); | ||||
for (state = ACPI_STATE_S1; state < ACPI_S_STATE_COUNT; state++) | for (state = ACPI_STATE_S1; state < ACPI_S_STATE_COUNT; state++) | ||||
if (acpi_sleep_states[state]) | if (acpi_sleep_states[state]) | ||||
sbuf_printf(&sb, "%s ", acpi_sstate2sname(state)); | sbuf_printf(&sb, "%s ", acpi_sstate2sname(state)); | ||||
#if defined(__i386__) || defined(__amd64__) | |||||
sbuf_printf(&sb, "S0IDLE "); | |||||
impUnsubmitted Not Done Inline ActionsI see s2idle and other things like that in the rest of the code. Do we need that here too? imp: I see s2idle and other things like that in the rest of the code. Do we need that here too?
| |||||
#endif | |||||
sbuf_trim(&sb); | sbuf_trim(&sb); | ||||
sbuf_finish(&sb); | sbuf_finish(&sb); | ||||
error = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); | error = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); | ||||
sbuf_delete(&sb); | sbuf_delete(&sb); | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
update_state(struct sysctl_oid *oidp, int new_state, int old_state) | |||||
{ | |||||
if (new_state < ACPI_STATE_S1) | |||||
return (EINVAL); | |||||
if (new_state < ACPI_S_STATE_COUNT && !acpi_sleep_states[new_state]) | |||||
return (EOPNOTSUPP); | |||||
if (new_state != old_state) | |||||
*(int *)oidp->oid_arg1 = new_state; | |||||
return (0); | |||||
} | |||||
static int | |||||
acpi_sleep_state_sysctl(SYSCTL_HANDLER_ARGS) | acpi_sleep_state_sysctl(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
#if defined(__i386__) || defined(__amd64__) | |||||
struct acpi_softc *sc; | |||||
char sleep_state[10]; | char sleep_state[10]; | ||||
int error, new_state, old_state; | int error, new_state, old_state; | ||||
int *sx, *saved_sx; | |||||
old_state = *(int *)oidp->oid_arg1; | old_state = *(int *)oidp->oid_arg1; | ||||
#define SETUP_VARIABLES(event) do { \ | |||||
sc = __containerof(__containerof(arg1, __typeof(sc->acpi_##event), sx), \ | |||||
struct acpi_softc, acpi_##event); \ | |||||
MPASS(sc); \ | |||||
sx = &sc->acpi_##event.sx; \ | |||||
MPASS(sx); \ | |||||
saved_sx = &sc->acpi_##event.saved_sx; \ | |||||
MPASS(saved_sx); \ | |||||
} while (0) | |||||
switch (arg2) { | |||||
case POWER_BUTTON_S2I: | |||||
SETUP_VARIABLES(power_button); | |||||
break; | |||||
case SLEEP_BUTTON_S2I: | |||||
SETUP_VARIABLES(sleep_button); | |||||
break; | |||||
case LID_SWITCH_S2I: | |||||
SETUP_VARIABLES(lid_switch); | |||||
break; | |||||
case STANDBY_S2I: | |||||
SETUP_VARIABLES(standby); | |||||
break; | |||||
case SUSPEND_S2I: | |||||
SETUP_VARIABLES(suspend); | |||||
break; | |||||
default: | |||||
__unreachable(); | |||||
}; | |||||
#undef SETUP_VARIABLES | |||||
if (*sx == SUSPEND_TO_IDLE) | |||||
strlcpy(sleep_state, "S0IDLE", 7); | |||||
else | |||||
strlcpy(sleep_state, acpi_sstate2sname(old_state), sizeof(sleep_state)); | strlcpy(sleep_state, acpi_sstate2sname(old_state), sizeof(sleep_state)); | ||||
error = sysctl_handle_string(oidp, sleep_state, sizeof(sleep_state), req); | error = sysctl_handle_string(oidp, sleep_state, sizeof(sleep_state), req); | ||||
if (error || req->newptr == NULL) | |||||
return (error); | |||||
if (*sx == acpi_sname2sstate(sleep_state)) | |||||
return (0); | |||||
/* When "enabling" s0idle, leave don't touch the default */ | |||||
if (!strncasecmp(sleep_state, "s0idle", 6) || | |||||
!strncasecmp(sleep_state, "s2idle", 6)) { | |||||
*saved_sx = *sx; | |||||
*sx = SUSPEND_TO_IDLE; | |||||
return (0); | |||||
} else { | |||||
new_state = acpi_sname2sstate(sleep_state); | |||||
error = update_state(oidp, new_state, old_state); | |||||
if (!error) | |||||
*saved_sx = *sx; | |||||
return (error); | |||||
} | |||||
#else | |||||
char sleep_state[10]; | |||||
int error, new_state, old_state; | |||||
old_state = *(int *)oidp->oid_arg1; | |||||
strlcpy(sleep_state, acpi_sstate2sname(old_state), sizeof(sleep_state)); | |||||
error = sysctl_handle_string(oidp, sleep_state, sizeof(sleep_state), req); | |||||
if (error == 0 && req->newptr != NULL) { | if (error == 0 && req->newptr != NULL) { | ||||
new_state = acpi_sname2sstate(sleep_state); | new_state = acpi_sname2sstate(sleep_state); | ||||
if (new_state < ACPI_STATE_S1) | error = update_state(oidp, new_state, old_state); | ||||
return (EINVAL); | |||||
if (new_state < ACPI_S_STATE_COUNT && !acpi_sleep_states[new_state]) | |||||
return (EOPNOTSUPP); | |||||
if (new_state != old_state) | |||||
*(int *)oidp->oid_arg1 = new_state; | |||||
} | } | ||||
return (error); | return (error); | ||||
#endif | |||||
} | } | ||||
/* Inform devctl(4) when we receive a Notify. */ | /* Inform devctl(4) when we receive a Notify. */ | ||||
void | void | ||||
acpi_UserNotify(const char *subsystem, ACPI_HANDLE h, uint8_t notify) | acpi_UserNotify(const char *subsystem, ACPI_HANDLE h, uint8_t notify) | ||||
{ | { | ||||
char notify_buf[16]; | char notify_buf[16]; | ||||
ACPI_BUFFER handle_buf; | ACPI_BUFFER handle_buf; | ||||
▲ Show 20 Lines • Show All 350 Lines • ▼ Show 20 Lines | case POWER_CMD_SUSPEND: | ||||
} | } | ||||
va_start(ap, arg); | va_start(ap, arg); | ||||
state = va_arg(ap, int); | state = va_arg(ap, int); | ||||
va_end(ap); | va_end(ap); | ||||
switch (state) { | switch (state) { | ||||
case POWER_SLEEP_STATE_STANDBY: | case POWER_SLEEP_STATE_STANDBY: | ||||
acpi_state = sc->acpi_standby_sx; | acpi_state = sc->acpi_standby.sx; | ||||
break; | break; | ||||
case POWER_SLEEP_STATE_SUSPEND: | case POWER_SLEEP_STATE_SUSPEND: | ||||
acpi_state = sc->acpi_suspend_sx; | acpi_state = sc->acpi_suspend.sx; | ||||
break; | break; | ||||
case POWER_SLEEP_STATE_HIBERNATE: | case POWER_SLEEP_STATE_HIBERNATE: | ||||
/* FIXME: Needs support for s2idle */ | |||||
acpi_state = ACPI_STATE_S4; | acpi_state = ACPI_STATE_S4; | ||||
break; | break; | ||||
default: | default: | ||||
error = EINVAL; | error = EINVAL; | ||||
goto out; | goto out; | ||||
} | } | ||||
if (ACPI_FAILURE(acpi_EnterSleepState(sc, acpi_state))) | if (ACPI_FAILURE(acpi_EnterSleepState(sc, acpi_state))) | ||||
Show All 21 Lines |
Would it be appropriate to have a printf here? I'm on the fence about this.