• R
    ACPICA: Introduce acpi_gpe_wakeup() · e8b6f970
    Rafael J. Wysocki 提交于
    ACPICA uses reference counters to avoid disabling GPEs too early in
    case they have been enabled for many times.  This is done separately
    for runtime and for wakeup, but the wakeup GPE reference counter is
    not really necessary, because GPEs are only enabled to wake up the
    system at the hardware level by acpi_enter_sleep_state().  Thus it
    only is necessary to set the corresponding bits in the wakeup enable
    masks of these GPEs' registers right before the system enters a sleep
    state.  Moreover, the GPE wakeup enable bits can only be set when the
    target sleep state of the system is known and they need to be cleared
    immediately after wakeup regardless of how many wakeup devices are
    associated with a given GPE.
    
    On the basis of the above observations, introduce function
    acpi_gpe_wakeup() to be used for setting or clearing the enable bit
    corresponding to a given GPE in its enable register's enable_for_wake
    mask.  Modify the ACPI suspend and wakeup code the use
    acpi_gpe_wakeup() instead of acpi_{enable|disable}_gpe() to set
    and clear GPE enable bits in their registers' enable_for_wake masks
    during system transitions to a sleep state and back to the working
    state, respectively.  [This will allow us to drop the third
    argument of acpi_{enable|disable}_gpe() and simplify the GPE
    handling code.]
    Signed-off-by: NRafael J. Wysocki <rjw@sisk.pl>
    Signed-off-by: NLen Brown <len.brown@intel.com>
    Signed-off-by: NBob Moore <robert.moore@intel.com>
    Signed-off-by: NLin Ming <ming.m.lin@intel.com>
    Signed-off-by: NLen Brown <len.brown@intel.com>
    e8b6f970
wakeup.c 3.3 KB
/*
 * wakeup.c - support wakeup devices
 * Copyright (C) 2004 Li Shaohua <shaohua.li@intel.com>
 */

#include <linux/init.h>
#include <linux/acpi.h>
#include <acpi/acpi_drivers.h>
#include <linux/kernel.h>
#include <linux/types.h>

#include "internal.h"
#include "sleep.h"

/*
 * We didn't lock acpi_device_lock in the file, because it invokes oops in
 * suspend/resume and isn't really required as this is called in S-state. At
 * that time, there is no device hotplug
 **/
#define _COMPONENT		ACPI_SYSTEM_COMPONENT
ACPI_MODULE_NAME("wakeup_devices")

/**
 * acpi_enable_wakeup_device_prep - Prepare wake-up devices.
 * @sleep_state: ACPI system sleep state.
 *
 * Enable all wake-up devices' power, unless the requested system sleep state is
 * too deep.
 */
void acpi_enable_wakeup_device_prep(u8 sleep_state)
{
	struct list_head *node, *next;

	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
		struct acpi_device *dev = container_of(node,
						       struct acpi_device,
						       wakeup_list);

		if (!dev->wakeup.flags.valid || !dev->wakeup.state.enabled
		    || (sleep_state > (u32) dev->wakeup.sleep_state))
			continue;

		acpi_enable_wakeup_device_power(dev, sleep_state);
	}
}

/**
 * acpi_enable_wakeup_device - Enable wake-up device GPEs.
 * @sleep_state: ACPI system sleep state.
 *
 * Enable all wake-up devices' GPEs, with the assumption that
 * acpi_disable_all_gpes() was executed before, so we don't need to disable any
 * GPEs here.
 */
void acpi_enable_wakeup_device(u8 sleep_state)
{
	struct list_head *node, *next;

	/* 
	 * Caution: this routine must be invoked when interrupt is disabled 
	 * Refer ACPI2.0: P212
	 */
	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
		struct acpi_device *dev =
			container_of(node, struct acpi_device, wakeup_list);

		if (!dev->wakeup.flags.valid
		    || !(dev->wakeup.state.enabled || dev->wakeup.prepare_count)
		    || sleep_state > (u32) dev->wakeup.sleep_state)
			continue;

		/* The wake-up power should have been enabled already. */
		acpi_gpe_wakeup(dev->wakeup.gpe_device, dev->wakeup.gpe_number,
				ACPI_GPE_ENABLE);
	}
}

/**
 * acpi_disable_wakeup_device - Disable devices' wakeup capability.
 * @sleep_state: ACPI system sleep state.
 *
 * This function only affects devices with wakeup.state.enabled set, which means
 * that it reverses the changes made by acpi_enable_wakeup_device_prep().
 */
void acpi_disable_wakeup_device(u8 sleep_state)
{
	struct list_head *node, *next;

	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
		struct acpi_device *dev =
			container_of(node, struct acpi_device, wakeup_list);

		if (!dev->wakeup.flags.valid
		    || !(dev->wakeup.state.enabled || dev->wakeup.prepare_count)
		    || (sleep_state > (u32) dev->wakeup.sleep_state))
			continue;

		acpi_gpe_wakeup(dev->wakeup.gpe_device, dev->wakeup.gpe_number,
				ACPI_GPE_DISABLE);

		if (dev->wakeup.state.enabled)
			acpi_disable_wakeup_device_power(dev);
	}
}

int __init acpi_wakeup_device_init(void)
{
	struct list_head *node, *next;

	mutex_lock(&acpi_device_lock);
	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
		struct acpi_device *dev = container_of(node,
						       struct acpi_device,
						       wakeup_list);
		if (dev->wakeup.flags.always_enabled)
			dev->wakeup.state.enabled = 1;
	}
	mutex_unlock(&acpi_device_lock);
	return 0;
}
反馈
建议
客服 返回
顶部