/*******************************************************************************
 *
 * FUNCTION:    acpi_enable_gpe
 *
 * PARAMETERS:  gpe_device      - Parent GPE Device. NULL for GPE0/GPE1
 *              gpe_number      - GPE level within the GPE block
 *              gpe_type        - ACPI_GPE_TYPE_RUNTIME or ACPI_GPE_TYPE_WAKE
 *                                or both
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is
 *              hardware-enabled (for runtime GPEs), or the GPE register mask
 *              is updated (for wake GPEs).
 *
 ******************************************************************************/
acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type)
{
	acpi_status status = AE_OK;
	struct acpi_gpe_event_info *gpe_event_info;
	acpi_cpu_flags flags;

	ACPI_FUNCTION_TRACE(acpi_enable_gpe);

	/* Parameter validation */

	if (!gpe_type || (gpe_type & ~ACPI_GPE_TYPE_WAKE_RUN)) {
		return_ACPI_STATUS(AE_BAD_PARAMETER);
	}

	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);

	/* Ensure that we have a valid GPE number */

	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
	if (!gpe_event_info) {
		status = AE_BAD_PARAMETER;
		goto unlock_and_exit;
	}

	if (gpe_type & ACPI_GPE_TYPE_RUNTIME) {
		if (gpe_event_info->runtime_count == ACPI_UINT8_MAX) {
			status = AE_LIMIT;	/* Too many references */
			goto unlock_and_exit;
		}

		gpe_event_info->runtime_count++;
		if (gpe_event_info->runtime_count == 1) {
			status = acpi_ev_enable_gpe(gpe_event_info);
			if (ACPI_FAILURE(status)) {
				gpe_event_info->runtime_count--;
				goto unlock_and_exit;
			}
		}
	}

	if (gpe_type & ACPI_GPE_TYPE_WAKE) {
		/* The GPE must have the ability to wake the system */

		if (!(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
			status = AE_TYPE;
			goto unlock_and_exit;
		}

		if (gpe_event_info->wakeup_count == ACPI_UINT8_MAX) {
			status = AE_LIMIT;	/* Too many references */
			goto unlock_and_exit;
		}

		/*
		 * Update the enable mask on the first wakeup reference. Wake GPEs
		 * are only hardware-enabled just before sleeping.
		 */
		gpe_event_info->wakeup_count++;
		if (gpe_event_info->wakeup_count == 1) {
			(void)acpi_ev_update_gpe_enable_masks(gpe_event_info);
		}
	}

unlock_and_exit:
	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
	return_ACPI_STATUS(status);
}
Exemple #2
0
/*******************************************************************************
 *
 * FUNCTION:    acpi_get_gpe_status
 *
 * PARAMETERS:  gpe_device      - Parent GPE Device. NULL for GPE0/GPE1
 *              gpe_number      - GPE level within the GPE block
 *              event_status    - Where the current status of the event will
 *                                be returned
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Get status of an event (general purpose)
 *
 ******************************************************************************/
acpi_status
acpi_get_gpe_status(acpi_handle gpe_device,
		    u32 gpe_number, acpi_event_status *event_status)
{
	acpi_status status = AE_OK;
	struct acpi_gpe_event_info *gpe_event_info;
	acpi_cpu_flags flags;

	ACPI_FUNCTION_TRACE(acpi_get_gpe_status);

	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);

	/* Ensure that we have a valid GPE number */

	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
	if (!gpe_event_info) {
		status = AE_BAD_PARAMETER;
		goto unlock_and_exit;
	}

	/* Obtain status on the requested GPE number */

	status = acpi_hw_get_gpe_status(gpe_event_info, event_status);

	if (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)
		*event_status |= ACPI_EVENT_FLAG_HANDLE;

      unlock_and_exit:
	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
	return_ACPI_STATUS(status);
}
Exemple #3
0
/*******************************************************************************
 *
 * FUNCTION:    acpi_set_gpe_type
 *
 * PARAMETERS:  gpe_device      - Parent GPE Device
 *              gpe_number      - GPE level within the GPE block
 *              Type            - New GPE type
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Set the type of an individual GPE
 *
 ******************************************************************************/
acpi_status acpi_set_gpe_type(acpi_handle gpe_device, u32 gpe_number, u8 type)
{
	acpi_status status = AE_OK;
	struct acpi_gpe_event_info *gpe_event_info;

	ACPI_FUNCTION_TRACE(acpi_set_gpe_type);

	/* Ensure that we have a valid GPE number */

	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
	if (!gpe_event_info) {
		status = AE_BAD_PARAMETER;
		goto unlock_and_exit;
	}

	if ((gpe_event_info->flags & ACPI_GPE_TYPE_MASK) == type) {
		return_ACPI_STATUS(AE_OK);
	}

	/* Set the new type (will disable GPE if currently enabled) */

	status = acpi_ev_set_gpe_type(gpe_event_info, type);

      unlock_and_exit:
	return_ACPI_STATUS(status);
}
Exemple #4
0
/*******************************************************************************
 *
 * FUNCTION:    acpi_gpe_can_wake
 *
 * PARAMETERS:  gpe_device      - Parent GPE Device. NULL for GPE0/GPE1
 *              gpe_number      - GPE level within the GPE block
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Set the ACPI_GPE_CAN_WAKE flag for the given GPE.  If the GPE
 *              has a corresponding method and is currently enabled, disable it
 *              (GPEs with corresponding methods are enabled unconditionally
 *              during initialization, but GPEs that can wake up are expected
 *              to be initially disabled).
 *
 ******************************************************************************/
acpi_status acpi_gpe_can_wake(acpi_handle gpe_device, u32 gpe_number)
{
	acpi_status status = AE_OK;
	struct acpi_gpe_event_info *gpe_event_info;
	acpi_cpu_flags flags;

	ACPI_FUNCTION_TRACE(acpi_gpe_can_wake);

	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);

	/* Ensure that we have a valid GPE number */

	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
	if (!gpe_event_info) {
		status = AE_BAD_PARAMETER;
		goto unlock_and_exit;
	}

	if (gpe_event_info->flags & ACPI_GPE_CAN_WAKE) {
		goto unlock_and_exit;
	}

	gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
	if (gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD) {
		(void)acpi_raw_disable_gpe(gpe_event_info);
	}

unlock_and_exit:
	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
	return_ACPI_STATUS(status);
}
Exemple #5
0
/*******************************************************************************
 *
 * FUNCTION:    acpi_clear_gpe
 *
 * PARAMETERS:  gpe_device      - Parent GPE Device
 *              gpe_number      - GPE level within the GPE block
 *              Flags           - Called from an ISR or not
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Clear an ACPI event (general purpose)
 *
 ******************************************************************************/
acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags)
{
	acpi_status status = AE_OK;
	struct acpi_gpe_event_info *gpe_event_info;

	ACPI_FUNCTION_TRACE(acpi_clear_gpe);

	/* Use semaphore lock if not executing at interrupt level */

	if (flags & ACPI_NOT_ISR) {
		status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
		if (ACPI_FAILURE(status)) {
			return_ACPI_STATUS(status);
		}
	}

	/* Ensure that we have a valid GPE number */

	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
	if (!gpe_event_info) {
		status = AE_BAD_PARAMETER;
		goto unlock_and_exit;
	}

	status = acpi_hw_clear_gpe(gpe_event_info);

      unlock_and_exit:
	if (flags & ACPI_NOT_ISR) {
		(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
	}
	return_ACPI_STATUS(status);
}
Exemple #6
0
/*******************************************************************************
 *
 * FUNCTION:    acpi_enable_gpe
 *
 * PARAMETERS:  gpe_device          - Parent GPE Device. NULL for GPE0/GPE1
 *              gpe_number          - GPE level within the GPE block
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is
 *              hardware-enabled.
 *
 ******************************************************************************/
acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
{
	acpi_status status = AE_BAD_PARAMETER;
	struct acpi_gpe_event_info *gpe_event_info;
	acpi_cpu_flags flags;

	ACPI_FUNCTION_TRACE(acpi_enable_gpe);

	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);

	/*
	 * Ensure that we have a valid GPE number and that there is some way
	 * of handling the GPE (handler or a GPE method). In other words, we
	 * won't allow a valid GPE to be enabled if there is no way to handle it.
	 */
	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
	if (gpe_event_info) {
		if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
		    ACPI_GPE_DISPATCH_NONE) {
			status = acpi_ev_add_gpe_reference(gpe_event_info);
		} else {
			status = AE_NO_HANDLER;
		}
	}

	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
	return_ACPI_STATUS(status);
}
Exemple #7
0
void acpi_db_generate_gpe(char *gpe_arg, char *block_arg)
{
	u32 block_number = 0;
	u32 gpe_number;
	struct acpi_gpe_event_info *gpe_event_info;

	gpe_number = strtoul(gpe_arg, NULL, 0);

	/*
	 * If no block arg, or block arg == 0 or 1, use the FADT-defined
	 * GPE blocks.
	 */
	if (block_arg) {
		block_number = strtoul(block_arg, NULL, 0);
		if (block_number == 1) {
			block_number = 0;
		}
	}

	gpe_event_info =
	    acpi_ev_get_gpe_event_info(ACPI_TO_POINTER(block_number),
				       gpe_number);
	if (!gpe_event_info) {
		acpi_os_printf("Invalid GPE\n");
		return;
	}

	(void)acpi_ev_gpe_dispatch(NULL, gpe_event_info, gpe_number);
}
Exemple #8
0
acpi_status acpi_set_gpe_wake_mask(acpi_handle gpe_device, u32 gpe_number, u8 action)
{
	acpi_status status = AE_OK;
	struct acpi_gpe_event_info *gpe_event_info;
	struct acpi_gpe_register_info *gpe_register_info;
	acpi_cpu_flags flags;
	u32 register_bit;

	ACPI_FUNCTION_TRACE(acpi_set_gpe_wake_mask);

	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);

	/*
	 * Ensure that we have a valid GPE number and that this GPE is in
	 * fact a wake GPE
	 */
	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
	if (!gpe_event_info) {
		status = AE_BAD_PARAMETER;
		goto unlock_and_exit;
	}

	if (!(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
		status = AE_TYPE;
		goto unlock_and_exit;
	}

	gpe_register_info = gpe_event_info->register_info;
	if (!gpe_register_info) {
		status = AE_NOT_EXIST;
		goto unlock_and_exit;
	}

	register_bit =
	    acpi_hw_get_gpe_register_bit(gpe_event_info, gpe_register_info);

	/* Perform the action */

	switch (action) {
	case ACPI_GPE_ENABLE:
		ACPI_SET_BIT(gpe_register_info->enable_for_wake,
			     (u8)register_bit);
		break;

	case ACPI_GPE_DISABLE:
		ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake,
			       (u8)register_bit);
		break;

	default:
		ACPI_ERROR((AE_INFO, "%u, Invalid action", action));
		status = AE_BAD_PARAMETER;
		break;
	}

unlock_and_exit:
	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
	return_ACPI_STATUS(status);
}
Exemple #9
0
/*******************************************************************************
 *
 * FUNCTION:    acpi_setup_gpe_for_wake
 *
 * PARAMETERS:  wake_device         - Device associated with the GPE (via _PRW)
 *              gpe_device          - Parent GPE Device. NULL for GPE0/GPE1
 *              gpe_number          - GPE level within the GPE block
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Mark a GPE as having the ability to wake the system. This
 *              interface is intended to be used as the host executes the
 *              _PRW methods (Power Resources for Wake) in the system tables.
 *              Each _PRW appears under a Device Object (The wake_device), and
 *              contains the info for the wake GPE associated with the
 *              wake_device.
 *
 ******************************************************************************/
acpi_status
acpi_setup_gpe_for_wake(acpi_handle wake_device,
			acpi_handle gpe_device, u32 gpe_number)
{
	acpi_status status = AE_BAD_PARAMETER;
	struct acpi_gpe_event_info *gpe_event_info;
	struct acpi_namespace_node *device_node;
	acpi_cpu_flags flags;

	ACPI_FUNCTION_TRACE(acpi_setup_gpe_for_wake);

	/* Parameter Validation */

	if (!wake_device) {
		/*
		 * By forcing wake_device to be valid, we automatically enable the
		 * implicit notify feature on all hosts.
		 */
		return_ACPI_STATUS(AE_BAD_PARAMETER);
	}

	/* Validate wake_device is of type Device */

	device_node = ACPI_CAST_PTR(struct acpi_namespace_node, wake_device);
	if (device_node->type != ACPI_TYPE_DEVICE) {
		return_ACPI_STATUS(AE_BAD_PARAMETER);
	}

	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);

	/* Ensure that we have a valid GPE number */

	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
	if (gpe_event_info) {
		/*
		 * If there is no method or handler for this GPE, then the
		 * wake_device will be notified whenever this GPE fires (aka
		 * "implicit notify") Note: The GPE is assumed to be
		 * level-triggered (for windows compatibility).
		 */
		if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
		    ACPI_GPE_DISPATCH_NONE) {
			gpe_event_info->flags =
			    (ACPI_GPE_DISPATCH_NOTIFY |
			     ACPI_GPE_LEVEL_TRIGGERED);
			gpe_event_info->dispatch.device_node = device_node;
		}

		gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
		status = AE_OK;
	}

	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
	return_ACPI_STATUS(status);
}
Exemple #10
0
/*******************************************************************************
 *
 * FUNCTION:    acpi_set_gpe
 *
 * PARAMETERS:  gpe_device          - Parent GPE Device. NULL for GPE0/GPE1
 *              gpe_number          - GPE level within the GPE block
 *              action              - ACPI_GPE_ENABLE or ACPI_GPE_DISABLE
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Enable or disable an individual GPE. This function bypasses
 *              the reference count mechanism used in the acpi_enable_gpe(),
 *              acpi_disable_gpe() interfaces.
 *              This API is typically used by the GPE raw handler mode driver
 *              to switch between the polling mode and the interrupt mode after
 *              the driver has enabled the GPE.
 *              The APIs should be invoked in this order:
 *               acpi_enable_gpe()            <- Ensure the reference count > 0
 *               acpi_set_gpe(ACPI_GPE_DISABLE) <- Enter polling mode
 *               acpi_set_gpe(ACPI_GPE_ENABLE) <- Leave polling mode
 *               acpi_disable_gpe()           <- Decrease the reference count
 *
 * Note: If a GPE is shared by 2 silicon components, then both the drivers
 *       should support GPE polling mode or disabling the GPE for long period
 *       for one driver may break the other. So use it with care since all
 *       firmware _Lxx/_Exx handlers currently rely on the GPE interrupt mode.
 *
 ******************************************************************************/
acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action)
{
	struct acpi_gpe_event_info *gpe_event_info;
	acpi_status status;
	acpi_cpu_flags flags;

	ACPI_FUNCTION_TRACE(acpi_set_gpe);

	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);

	/* Ensure that we have a valid GPE number */

	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
	if (!gpe_event_info) {
		status = AE_BAD_PARAMETER;
		goto unlock_and_exit;
	}

	/* Perform the action */

	switch (action) {
	case ACPI_GPE_ENABLE:

		status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE);
		gpe_event_info->disable_for_dispatch = FALSE;
		break;

	case ACPI_GPE_DISABLE:

		status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
		gpe_event_info->disable_for_dispatch = TRUE;
		break;

	default:

		status = AE_BAD_PARAMETER;
		break;
	}

unlock_and_exit:
	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
	return_ACPI_STATUS(status);
}
Exemple #11
0
/*******************************************************************************
 *
 * FUNCTION:    acpi_disable_gpe
 *
 * PARAMETERS:  gpe_device      - Parent GPE Device. NULL for GPE0/GPE1
 *              gpe_number      - GPE level within the GPE block
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Remove a reference to a GPE. When the last reference is
 *              removed, only then is the GPE disabled (for runtime GPEs), or
 *              the GPE mask bit disabled (for wake GPEs)
 *
 ******************************************************************************/
acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number)
{
	acpi_status status = AE_BAD_PARAMETER;
	struct acpi_gpe_event_info *gpe_event_info;
	acpi_cpu_flags flags;

	ACPI_FUNCTION_TRACE(acpi_disable_gpe);

	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);

	/* Ensure that we have a valid GPE number */

	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
	if (gpe_event_info) {
		status = acpi_raw_disable_gpe(gpe_event_info) ;
	}

	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
	return_ACPI_STATUS(status);
}
Exemple #12
0
/*******************************************************************************
 *
 * FUNCTION:    acpi_gpe_can_wake
 *
 * PARAMETERS:  gpe_device      - Parent GPE Device. NULL for GPE0/GPE1
 *              gpe_number      - GPE level within the GPE block
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Set the ACPI_GPE_CAN_WAKE flag for the given GPE.  If the GPE
 *              has a corresponding method and is currently enabled, disable it
 *              (GPEs with corresponding methods are enabled unconditionally
 *              during initialization, but GPEs that can wake up are expected
 *              to be initially disabled).
 *
 ******************************************************************************/
acpi_status acpi_gpe_can_wake(acpi_handle gpe_device, u32 gpe_number)
{
	acpi_status status = AE_OK;
	struct acpi_gpe_event_info *gpe_event_info;
	acpi_cpu_flags flags;

	ACPI_FUNCTION_TRACE(acpi_gpe_can_wake);

	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);

	/* Ensure that we have a valid GPE number */

	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
	if (gpe_event_info) {
		gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
	} else {
		status = AE_BAD_PARAMETER;
	}

	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
	return_ACPI_STATUS(status);
}
Exemple #13
0
/*******************************************************************************
 *
 * FUNCTION:    acpi_mask_gpe
 *
 * PARAMETERS:  gpe_device          - Parent GPE Device. NULL for GPE0/GPE1
 *              gpe_number          - GPE level within the GPE block
 *              is_masked           - Whether the GPE is masked or not
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Unconditionally mask/unmask the an individual GPE, ex., to
 *              prevent a GPE flooding.
 *
 ******************************************************************************/
acpi_status acpi_mask_gpe(acpi_handle gpe_device, u32 gpe_number, u8 is_masked)
{
	struct acpi_gpe_event_info *gpe_event_info;
	acpi_status status;
	acpi_cpu_flags flags;

	ACPI_FUNCTION_TRACE(acpi_mask_gpe);

	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);

	/* Ensure that we have a valid GPE number */

	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
	if (!gpe_event_info) {
		status = AE_BAD_PARAMETER;
		goto unlock_and_exit;
	}

	status = acpi_ev_mask_gpe(gpe_event_info, is_masked);

unlock_and_exit:
	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
	return_ACPI_STATUS(status);
}
Exemple #14
0
acpi_status
acpi_remove_gpe_handler(acpi_handle gpe_device,
			u32 gpe_number, acpi_event_handler address)
{
	struct acpi_gpe_event_info *gpe_event_info;
	struct acpi_handler_info *handler;
	acpi_status status;
	acpi_cpu_flags flags;

	ACPI_FUNCTION_TRACE(acpi_remove_gpe_handler);

	

	if (!address) {
		return_ACPI_STATUS(AE_BAD_PARAMETER);
	}

	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
	}

	

	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
	if (!gpe_event_info) {
		status = AE_BAD_PARAMETER;
		goto unlock_and_exit;
	}

	

	if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) !=
	    ACPI_GPE_DISPATCH_HANDLER) {
		status = AE_NOT_EXIST;
		goto unlock_and_exit;
	}

	

	if (gpe_event_info->dispatch.handler->address != address) {
		status = AE_BAD_PARAMETER;
		goto unlock_and_exit;
	}

	

	status = acpi_ev_disable_gpe(gpe_event_info);
	if (ACPI_FAILURE(status)) {
		goto unlock_and_exit;
	}

	

	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
	acpi_os_wait_events_complete(NULL);
	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
	}

	

	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
	handler = gpe_event_info->dispatch.handler;

	

	gpe_event_info->dispatch.method_node = handler->method_node;
	gpe_event_info->flags &= ~ACPI_GPE_DISPATCH_MASK;	
	if (handler->method_node) {
		gpe_event_info->flags |= ACPI_GPE_DISPATCH_METHOD;
	}
	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);

	

	ACPI_FREE(handler);

      unlock_and_exit:
	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
	return_ACPI_STATUS(status);
}
Exemple #15
0
/*******************************************************************************
 *
 * FUNCTION:    acpi_setup_gpe_for_wake
 *
 * PARAMETERS:  wake_device         - Device associated with the GPE (via _PRW)
 *              gpe_device          - Parent GPE Device. NULL for GPE0/GPE1
 *              gpe_number          - GPE level within the GPE block
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Mark a GPE as having the ability to wake the system. This
 *              interface is intended to be used as the host executes the
 *              _PRW methods (Power Resources for Wake) in the system tables.
 *              Each _PRW appears under a Device Object (The wake_device), and
 *              contains the info for the wake GPE associated with the
 *              wake_device.
 *
 ******************************************************************************/
acpi_status
acpi_setup_gpe_for_wake(acpi_handle wake_device,
			acpi_handle gpe_device, u32 gpe_number)
{
	acpi_status status;
	struct acpi_gpe_event_info *gpe_event_info;
	struct acpi_namespace_node *device_node;
	struct acpi_gpe_notify_info *notify;
	struct acpi_gpe_notify_info *new_notify;
	acpi_cpu_flags flags;

	ACPI_FUNCTION_TRACE(acpi_setup_gpe_for_wake);

	/* Parameter Validation */

	if (!wake_device) {
		/*
		 * By forcing wake_device to be valid, we automatically enable the
		 * implicit notify feature on all hosts.
		 */
		return_ACPI_STATUS(AE_BAD_PARAMETER);
	}

	/* Handle root object case */

	if (wake_device == ACPI_ROOT_OBJECT) {
		device_node = acpi_gbl_root_node;
	} else {
		device_node =
		    ACPI_CAST_PTR(struct acpi_namespace_node, wake_device);
	}

	/* Validate wake_device is of type Device */

	if (device_node->type != ACPI_TYPE_DEVICE) {
		return_ACPI_STATUS (AE_BAD_PARAMETER);
	}

	/*
	 * Allocate a new notify object up front, in case it is needed.
	 * Memory allocation while holding a spinlock is a big no-no
	 * on some hosts.
	 */
	new_notify = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_notify_info));
	if (!new_notify) {
		return_ACPI_STATUS(AE_NO_MEMORY);
	}

	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);

	/* Ensure that we have a valid GPE number */

	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
	if (!gpe_event_info) {
		status = AE_BAD_PARAMETER;
		goto unlock_and_exit;
	}

	/*
	 * If there is no method or handler for this GPE, then the
	 * wake_device will be notified whenever this GPE fires. This is
	 * known as an "implicit notify". Note: The GPE is assumed to be
	 * level-triggered (for windows compatibility).
	 */
	if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
	    ACPI_GPE_DISPATCH_NONE) {
		/*
		 * This is the first device for implicit notify on this GPE.
		 * Just set the flags here, and enter the NOTIFY block below.
		 */
		gpe_event_info->flags =
		    (ACPI_GPE_DISPATCH_NOTIFY | ACPI_GPE_LEVEL_TRIGGERED);
	}

	/*
	 * If we already have an implicit notify on this GPE, add
	 * this device to the notify list.
	 */
	if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
	    ACPI_GPE_DISPATCH_NOTIFY) {

		/* Ensure that the device is not already in the list */

		notify = gpe_event_info->dispatch.notify_list;
		while (notify) {
			if (notify->device_node == device_node) {
				status = AE_ALREADY_EXISTS;
				goto unlock_and_exit;
			}
			notify = notify->next;
		}

		/* Add this device to the notify list for this GPE */

		new_notify->device_node = device_node;
		new_notify->next = gpe_event_info->dispatch.notify_list;
		gpe_event_info->dispatch.notify_list = new_notify;
		new_notify = NULL;
	}

	/* Mark the GPE as a possible wake event */

	gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
	status = AE_OK;

unlock_and_exit:
	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);

	/* Delete the notify object if it was not used above */

	if (new_notify) {
		ACPI_FREE(new_notify);
	}
	return_ACPI_STATUS(status);
}
/*******************************************************************************
 *
 * FUNCTION:    acpi_install_gpe_handler
 *
 * PARAMETERS:  gpe_device      - Namespace node for the GPE (NULL for FADT
 *                                defined GPEs)
 *              gpe_number      - The GPE number within the GPE block
 *              Type            - Whether this GPE should be treated as an
 *                                edge- or level-triggered interrupt.
 *              Address         - Address of the handler
 *              Context         - Value passed to the handler on each GPE
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Install a handler for a General Purpose Event.
 *
 ******************************************************************************/
acpi_status
acpi_install_gpe_handler(acpi_handle gpe_device,
			 u32 gpe_number,
			 u32 type, acpi_event_handler address, void *context)
{
	struct acpi_gpe_event_info *gpe_event_info;
	struct acpi_handler_info *handler;
	acpi_status status;
	acpi_cpu_flags flags;

	ACPI_FUNCTION_TRACE(acpi_install_gpe_handler);

	/* Parameter validation */

	if ((!address) || (type > ACPI_GPE_XRUPT_TYPE_MASK)) {
		status = AE_BAD_PARAMETER;
		goto exit;
	}

	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
	if (ACPI_FAILURE(status)) {
		goto exit;
	}

	/* Ensure that we have a valid GPE number */

	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
	if (!gpe_event_info) {
		status = AE_BAD_PARAMETER;
		goto unlock_and_exit;
	}

	/* Make sure that there isn't a handler there already */

	if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
	    ACPI_GPE_DISPATCH_HANDLER) {
		status = AE_ALREADY_EXISTS;
		goto unlock_and_exit;
	}

	/* Allocate and init handler object */

	handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_handler_info));
	if (!handler) {
		status = AE_NO_MEMORY;
		goto unlock_and_exit;
	}

	handler->address = address;
	handler->context = context;
	handler->method_node = gpe_event_info->dispatch.method_node;

	/* Disable the GPE before installing the handler */

	status = acpi_ev_disable_gpe(gpe_event_info);
	if (ACPI_FAILURE(status)) {
		goto unlock_and_exit;
	}

	/* Install the handler */

	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
	gpe_event_info->dispatch.handler = handler;

	/* Setup up dispatch flags to indicate handler (vs. method) */

	gpe_event_info->flags &=
	    ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
	gpe_event_info->flags |= (u8) (type | ACPI_GPE_DISPATCH_HANDLER);

	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);

      unlock_and_exit:
	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
      exit:
	if (ACPI_FAILURE(status))
		ACPI_EXCEPTION((AE_INFO, status,
				"Installing notify handler failed"));
	return_ACPI_STATUS(status);
}
/*******************************************************************************
 *
 * FUNCTION:    acpi_remove_gpe_handler
 *
 * PARAMETERS:  gpe_device      - Namespace node for the GPE (NULL for FADT
 *                                defined GPEs)
 *              gpe_number      - The event to remove a handler
 *              Address         - Address of the handler
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Remove a handler for a General Purpose acpi_event.
 *
 ******************************************************************************/
acpi_status
acpi_remove_gpe_handler(acpi_handle gpe_device,
			u32 gpe_number, acpi_event_handler address)
{
	struct acpi_gpe_event_info *gpe_event_info;
	struct acpi_handler_info *handler;
	acpi_status status;
	acpi_cpu_flags flags;

	ACPI_FUNCTION_TRACE(acpi_remove_gpe_handler);

	/* Parameter validation */

	if (!address) {
		return_ACPI_STATUS(AE_BAD_PARAMETER);
	}

	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
	}

	/* Ensure that we have a valid GPE number */

	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
	if (!gpe_event_info) {
		status = AE_BAD_PARAMETER;
		goto unlock_and_exit;
	}

	/* Make sure that a handler is indeed installed */

	if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) !=
	    ACPI_GPE_DISPATCH_HANDLER) {
		status = AE_NOT_EXIST;
		goto unlock_and_exit;
	}

	/* Make sure that the installed handler is the same */

	if (gpe_event_info->dispatch.handler->address != address) {
		status = AE_BAD_PARAMETER;
		goto unlock_and_exit;
	}

	/* Disable the GPE before removing the handler */

	status = acpi_ev_disable_gpe(gpe_event_info);
	if (ACPI_FAILURE(status)) {
		goto unlock_and_exit;
	}

	/* Make sure all deferred tasks are completed */

	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
	acpi_os_wait_events_complete(NULL);
	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
	}

	/* Remove the handler */

	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
	handler = gpe_event_info->dispatch.handler;

	/* Restore Method node (if any), set dispatch flags */

	gpe_event_info->dispatch.method_node = handler->method_node;
	gpe_event_info->flags &= ~ACPI_GPE_DISPATCH_MASK;	/* Clear bits */
	if (handler->method_node) {
		gpe_event_info->flags |= ACPI_GPE_DISPATCH_METHOD;
	}
	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);

	/* Now we can free the handler object */

	ACPI_FREE(handler);

      unlock_and_exit:
	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
	return_ACPI_STATUS(status);
}
Exemple #18
0
/*******************************************************************************
 *
 * FUNCTION:    acpi_install_gpe_handler
 *
 * PARAMETERS:  gpe_device      - Namespace node for the GPE (NULL for FADT
 *                                defined GPEs)
 *              gpe_number      - The GPE number within the GPE block
 *              Type            - Whether this GPE should be treated as an
 *                                edge- or level-triggered interrupt.
 *              Address         - Address of the handler
 *              Context         - Value passed to the handler on each GPE
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Install a handler for a General Purpose Event.
 *
 ******************************************************************************/
acpi_status
acpi_install_gpe_handler(acpi_handle gpe_device,
			 u32 gpe_number,
			 u32 type, acpi_gpe_handler address, void *context)
{
	struct acpi_gpe_event_info *gpe_event_info;
	struct acpi_gpe_handler_info *handler;
	acpi_status status;
	acpi_cpu_flags flags;

	ACPI_FUNCTION_TRACE(acpi_install_gpe_handler);

	/* Parameter validation */

	if ((!address) || (type & ~ACPI_GPE_XRUPT_TYPE_MASK)) {
		return_ACPI_STATUS(AE_BAD_PARAMETER);
	}

	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
	}

	/* Allocate memory for the handler object */

	handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_handler_info));
	if (!handler) {
		status = AE_NO_MEMORY;
		goto unlock_and_exit;
	}

	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);

	/* Ensure that we have a valid GPE number */

	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
	if (!gpe_event_info) {
		status = AE_BAD_PARAMETER;
		goto free_and_exit;
	}

	/* Make sure that there isn't a handler there already */

	if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
	    ACPI_GPE_DISPATCH_HANDLER) {
		status = AE_ALREADY_EXISTS;
		goto free_and_exit;
	}

	/* Allocate and init handler object */

	handler->address = address;
	handler->context = context;
	handler->method_node = gpe_event_info->dispatch.method_node;
	handler->original_flags = gpe_event_info->flags &
			(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);

	/*
	 * If the GPE is associated with a method, it might have been enabled
	 * automatically during initialization, in which case it has to be
	 * disabled now to avoid spurious execution of the handler.
	 */

	if ((handler->original_flags & ACPI_GPE_DISPATCH_METHOD)
	    && gpe_event_info->runtime_count) {
		handler->originally_enabled = 1;
		(void)acpi_ev_remove_gpe_reference(gpe_event_info);
	}

	/* Install the handler */

	gpe_event_info->dispatch.handler = handler;

	/* Setup up dispatch flags to indicate handler (vs. method) */

	gpe_event_info->flags &=
	    ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
	gpe_event_info->flags |= (u8) (type | ACPI_GPE_DISPATCH_HANDLER);

	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);

unlock_and_exit:
	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
	return_ACPI_STATUS(status);

free_and_exit:
	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
	ACPI_FREE(handler);
	goto unlock_and_exit;
}
Exemple #19
0
/*******************************************************************************
 *
 * FUNCTION:    acpi_remove_gpe_handler
 *
 * PARAMETERS:  gpe_device      - Namespace node for the GPE (NULL for FADT
 *                                defined GPEs)
 *              gpe_number      - The event to remove a handler
 *              Address         - Address of the handler
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Remove a handler for a General Purpose acpi_event.
 *
 ******************************************************************************/
acpi_status
acpi_remove_gpe_handler(acpi_handle gpe_device,
			u32 gpe_number, acpi_gpe_handler address)
{
	struct acpi_gpe_event_info *gpe_event_info;
	struct acpi_gpe_handler_info *handler;
	acpi_status status;
	acpi_cpu_flags flags;

	ACPI_FUNCTION_TRACE(acpi_remove_gpe_handler);

	/* Parameter validation */

	if (!address) {
		return_ACPI_STATUS(AE_BAD_PARAMETER);
	}

	/* Make sure all deferred tasks are completed */

	acpi_os_wait_events_complete(NULL);

	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
	}

	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);

	/* Ensure that we have a valid GPE number */

	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
	if (!gpe_event_info) {
		status = AE_BAD_PARAMETER;
		goto unlock_and_exit;
	}

	/* Make sure that a handler is indeed installed */

	if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) !=
	    ACPI_GPE_DISPATCH_HANDLER) {
		status = AE_NOT_EXIST;
		goto unlock_and_exit;
	}

	/* Make sure that the installed handler is the same */

	if (gpe_event_info->dispatch.handler->address != address) {
		status = AE_BAD_PARAMETER;
		goto unlock_and_exit;
	}

	/* Remove the handler */

	handler = gpe_event_info->dispatch.handler;

	/* Restore Method node (if any), set dispatch flags */

	gpe_event_info->dispatch.method_node = handler->method_node;
	gpe_event_info->flags &=
		~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
	gpe_event_info->flags |= handler->original_flags;

	/*
	 * If the GPE was previously associated with a method and it was
	 * enabled, it should be enabled at this point to restore the
	 * post-initialization configuration.
	 */

	if ((handler->original_flags & ACPI_GPE_DISPATCH_METHOD)
	    && handler->originally_enabled)
		(void)acpi_ev_add_gpe_reference(gpe_event_info);

	/* Now we can free the handler object */

	ACPI_FREE(handler);

unlock_and_exit:
	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);

	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
	return_ACPI_STATUS(status);
}
Exemple #20
0
acpi_status
acpi_install_gpe_handler(acpi_handle gpe_device,
			 u32 gpe_number,
			 u32 type, acpi_event_handler address, void *context)
{
	struct acpi_gpe_event_info *gpe_event_info;
	struct acpi_handler_info *handler;
	acpi_status status;
	acpi_cpu_flags flags;

	ACPI_FUNCTION_TRACE(acpi_install_gpe_handler);

	

	if ((!address) || (type > ACPI_GPE_XRUPT_TYPE_MASK)) {
		status = AE_BAD_PARAMETER;
		goto exit;
	}

	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
	if (ACPI_FAILURE(status)) {
		goto exit;
	}

	

	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
	if (!gpe_event_info) {
		status = AE_BAD_PARAMETER;
		goto unlock_and_exit;
	}

	

	if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
	    ACPI_GPE_DISPATCH_HANDLER) {
		status = AE_ALREADY_EXISTS;
		goto unlock_and_exit;
	}

	

	handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_handler_info));
	if (!handler) {
		status = AE_NO_MEMORY;
		goto unlock_and_exit;
	}

	handler->address = address;
	handler->context = context;
	handler->method_node = gpe_event_info->dispatch.method_node;

	

	status = acpi_ev_disable_gpe(gpe_event_info);
	if (ACPI_FAILURE(status)) {
		goto unlock_and_exit;
	}

	

	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
	gpe_event_info->dispatch.handler = handler;

	

	gpe_event_info->flags &=
	    ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
	gpe_event_info->flags |= (u8) (type | ACPI_GPE_DISPATCH_HANDLER);

	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);

      unlock_and_exit:
	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
      exit:
	if (ACPI_FAILURE(status))
		ACPI_EXCEPTION((AE_INFO, status,
				"Installing notify handler failed"));
	return_ACPI_STATUS(status);
}
/*******************************************************************************
 *
 * FUNCTION:    acpi_disable_gpe
 *
 * PARAMETERS:  gpe_device      - Parent GPE Device. NULL for GPE0/GPE1
 *              gpe_number      - GPE level within the GPE block
 *              gpe_type        - ACPI_GPE_TYPE_RUNTIME or ACPI_GPE_TYPE_WAKE
 *                                or both
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Remove a reference to a GPE. When the last reference is
 *              removed, only then is the GPE disabled (for runtime GPEs), or
 *              the GPE mask bit disabled (for wake GPEs)
 *
 ******************************************************************************/
acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type)
{
	acpi_status status = AE_OK;
	struct acpi_gpe_event_info *gpe_event_info;
	acpi_cpu_flags flags;

	ACPI_FUNCTION_TRACE(acpi_disable_gpe);

	/* Parameter validation */

	if (!gpe_type || (gpe_type & ~ACPI_GPE_TYPE_WAKE_RUN)) {
		return_ACPI_STATUS(AE_BAD_PARAMETER);
	}

	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);

	/* Ensure that we have a valid GPE number */

	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
	if (!gpe_event_info) {
		status = AE_BAD_PARAMETER;
		goto unlock_and_exit;
	}

	/* Hardware-disable a runtime GPE on removal of the last reference */

	if (gpe_type & ACPI_GPE_TYPE_RUNTIME) {
		if (!gpe_event_info->runtime_count) {
			status = AE_LIMIT;	/* There are no references to remove */
			goto unlock_and_exit;
		}

		gpe_event_info->runtime_count--;
		if (!gpe_event_info->runtime_count) {
			status = acpi_ev_disable_gpe(gpe_event_info);
			if (ACPI_FAILURE(status)) {
				gpe_event_info->runtime_count++;
				goto unlock_and_exit;
			}
		}
	}

	/*
	 * Update masks for wake GPE on removal of the last reference.
	 * No need to hardware-disable wake GPEs here, they are not currently
	 * enabled.
	 */
	if (gpe_type & ACPI_GPE_TYPE_WAKE) {
		if (!gpe_event_info->wakeup_count) {
			status = AE_LIMIT;	/* There are no references to remove */
			goto unlock_and_exit;
		}

		gpe_event_info->wakeup_count--;
		if (!gpe_event_info->wakeup_count) {
			(void)acpi_ev_update_gpe_enable_masks(gpe_event_info);
		}
	}

unlock_and_exit:
	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
	return_ACPI_STATUS(status);
}
Exemple #22
0
/*******************************************************************************
 *
 * FUNCTION:    acpi_setup_gpe_for_wake
 *
 * PARAMETERS:  wake_device         - Device associated with the GPE (via _PRW)
 *              gpe_device          - Parent GPE Device. NULL for GPE0/GPE1
 *              gpe_number          - GPE level within the GPE block
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Mark a GPE as having the ability to wake the system. This
 *              interface is intended to be used as the host executes the
 *              _PRW methods (Power Resources for Wake) in the system tables.
 *              Each _PRW appears under a Device Object (The wake_device), and
 *              contains the info for the wake GPE associated with the
 *              wake_device.
 *
 ******************************************************************************/
acpi_status
acpi_setup_gpe_for_wake(acpi_handle wake_device,
                        acpi_handle gpe_device, u32 gpe_number)
{
    acpi_status status = AE_BAD_PARAMETER;
    struct acpi_gpe_event_info *gpe_event_info;
    struct acpi_namespace_node *device_node;
    struct acpi_gpe_notify_object *notify_object;
    acpi_cpu_flags flags;
    u8 gpe_dispatch_mask;

    ACPI_FUNCTION_TRACE(acpi_setup_gpe_for_wake);

    /* Parameter Validation */

    if (!wake_device) {
        /*
         * By forcing wake_device to be valid, we automatically enable the
         * implicit notify feature on all hosts.
         */
        return_ACPI_STATUS(AE_BAD_PARAMETER);
    }

    flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);

    /* Ensure that we have a valid GPE number */

    gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
    if (!gpe_event_info) {
        goto unlock_and_exit;
    }

    if (wake_device == ACPI_ROOT_OBJECT) {
        goto out;
    }

    /*
     * If there is no method or handler for this GPE, then the
     * wake_device will be notified whenever this GPE fires (aka
     * "implicit notify") Note: The GPE is assumed to be
     * level-triggered (for windows compatibility).
     */
    gpe_dispatch_mask = gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK;
    if (gpe_dispatch_mask != ACPI_GPE_DISPATCH_NONE
            && gpe_dispatch_mask != ACPI_GPE_DISPATCH_NOTIFY) {
        goto out;
    }

    /* Validate wake_device is of type Device */

    device_node = ACPI_CAST_PTR(struct acpi_namespace_node, wake_device);
    if (device_node->type != ACPI_TYPE_DEVICE) {
        goto unlock_and_exit;
    }

    if (gpe_dispatch_mask == ACPI_GPE_DISPATCH_NONE) {
        gpe_event_info->flags = (ACPI_GPE_DISPATCH_NOTIFY |
                                 ACPI_GPE_LEVEL_TRIGGERED);
        gpe_event_info->dispatch.device.node = device_node;
        gpe_event_info->dispatch.device.next = NULL;
    } else {
        /* There are multiple devices to notify implicitly. */

        notify_object = ACPI_ALLOCATE_ZEROED(sizeof(*notify_object));
        if (!notify_object) {
            status = AE_NO_MEMORY;
            goto unlock_and_exit;
        }

        notify_object->node = device_node;
        notify_object->next = gpe_event_info->dispatch.device.next;
        gpe_event_info->dispatch.device.next = notify_object;
    }

out:
    gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
    status = AE_OK;

unlock_and_exit:
    acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
    return_ACPI_STATUS(status);
}