/*******************************************************************************
 *
 * 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);
}
Exemplo n.º 2
0
acpi_status
acpi_ev_enable_gpe (
	struct acpi_gpe_event_info      *gpe_event_info,
	u8                              write_to_hardware)
{
	acpi_status                     status;


	ACPI_FUNCTION_TRACE ("ev_enable_gpe");


	/* Make sure HW enable masks are updated */

	status = acpi_ev_update_gpe_enable_masks (gpe_event_info, ACPI_GPE_ENABLE);
	if (ACPI_FAILURE (status)) {
		return_ACPI_STATUS (status);
	}

	/* Mark wake-enabled or HW enable, or both */

	switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) {
	case ACPI_GPE_TYPE_WAKE:

		ACPI_SET_BIT (gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);
		break;

	case ACPI_GPE_TYPE_WAKE_RUN:

		ACPI_SET_BIT (gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);

		/*lint -fallthrough */

	case ACPI_GPE_TYPE_RUNTIME:

		ACPI_SET_BIT (gpe_event_info->flags, ACPI_GPE_RUN_ENABLED);

		if (write_to_hardware) {
			/* Clear the GPE (of stale events), then enable it */

			status = acpi_hw_clear_gpe (gpe_event_info);
			if (ACPI_FAILURE (status)) {
				return_ACPI_STATUS (status);
			}

			/* Enable the requested runtime GPE */

			status = acpi_hw_write_gpe_enable_reg (gpe_event_info);
		}
		break;

	default:
		return_ACPI_STATUS (AE_BAD_PARAMETER);
	}

	return_ACPI_STATUS (AE_OK);
}
Exemplo n.º 3
0
acpi_status
acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info,
		   u8 write_to_hardware)
{
	acpi_status status;

	ACPI_FUNCTION_TRACE(ev_enable_gpe);

	

	status =
	    acpi_ev_update_gpe_enable_masks(gpe_event_info, ACPI_GPE_ENABLE);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
	}

	

	switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) {
	case ACPI_GPE_TYPE_WAKE:

		ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);
		break;

	case ACPI_GPE_TYPE_WAKE_RUN:

		ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);

		

	case ACPI_GPE_TYPE_RUNTIME:

		ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED);

		if (write_to_hardware) {

			

			status = acpi_hw_clear_gpe(gpe_event_info);
			if (ACPI_FAILURE(status)) {
				return_ACPI_STATUS(status);
			}

			

			status = acpi_hw_write_gpe_enable_reg(gpe_event_info);
		}
		break;

	default:
		return_ACPI_STATUS(AE_BAD_PARAMETER);
	}

	return_ACPI_STATUS(AE_OK);
}
Exemplo n.º 4
0
acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
{
    acpi_status status;

    ACPI_FUNCTION_TRACE(ev_disable_gpe);

    /* Make sure HW enable masks are updated */

    status =
        acpi_ev_update_gpe_enable_masks(gpe_event_info, ACPI_GPE_DISABLE);
    if (ACPI_FAILURE(status)) {
        return_ACPI_STATUS(status);
    }

    /* Clear the appropriate enabled flags for this GPE */

    switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) {
    case ACPI_GPE_TYPE_WAKE:
        ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);
        break;

    case ACPI_GPE_TYPE_WAKE_RUN:
        ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);

    /* fallthrough */

    case ACPI_GPE_TYPE_RUNTIME:

        /* Disable the requested runtime GPE */

        ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED);
        break;

    default:
        break;
    }

    /*
     * Even if we don't know the GPE type, make sure that we always
     * disable it. low_disable_gpe will just clear the enable bit for this
     * GPE and write it. It will not write out the current GPE enable mask,
     * since this may inadvertently enable GPEs too early, if a rogue GPE has
     * come in during ACPICA initialization - possibly as a result of AML or
     * other code that has enabled the GPE.
     */
    status = acpi_hw_low_disable_gpe(gpe_event_info);
    return_ACPI_STATUS(status);
}
Exemplo n.º 5
0
acpi_status
acpi_ev_disable_gpe (
	struct acpi_gpe_event_info      *gpe_event_info)
{
	acpi_status                     status;


	ACPI_FUNCTION_TRACE ("ev_disable_gpe");


	if (!(gpe_event_info->flags & ACPI_GPE_ENABLE_MASK)) {
		return_ACPI_STATUS (AE_OK);
	}

	/* Make sure HW enable masks are updated */

	status = acpi_ev_update_gpe_enable_masks (gpe_event_info, ACPI_GPE_DISABLE);
	if (ACPI_FAILURE (status)) {
		return_ACPI_STATUS (status);
	}

	/* Mark wake-disabled or HW disable, or both */

	switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) {
	case ACPI_GPE_TYPE_WAKE:
		ACPI_CLEAR_BIT (gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);
		break;

	case ACPI_GPE_TYPE_WAKE_RUN:
		ACPI_CLEAR_BIT (gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);

		/*lint -fallthrough */

	case ACPI_GPE_TYPE_RUNTIME:

		/* Disable the requested runtime GPE */

		ACPI_CLEAR_BIT (gpe_event_info->flags, ACPI_GPE_RUN_ENABLED);
		status = acpi_hw_write_gpe_enable_reg (gpe_event_info);
		break;

	default:
		return_ACPI_STATUS (AE_BAD_PARAMETER);
	}

	return_ACPI_STATUS (AE_OK);
}
Exemplo n.º 6
0
acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
{
	acpi_status status;

	ACPI_FUNCTION_TRACE(ev_disable_gpe);

	

	status =
	    acpi_ev_update_gpe_enable_masks(gpe_event_info, ACPI_GPE_DISABLE);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
	}

	

	switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) {
	case ACPI_GPE_TYPE_WAKE:
		ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);
		break;

	case ACPI_GPE_TYPE_WAKE_RUN:
		ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);

		

	case ACPI_GPE_TYPE_RUNTIME:

		

		ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED);
		break;

	default:
		break;
	}

	
	status = acpi_hw_low_disable_gpe(gpe_event_info);
	return_ACPI_STATUS(status);
}
Exemplo n.º 7
0
static acpi_status
acpi_ev_match_prw_and_gpe(acpi_handle obj_handle,
              u32 level, void *info, void **return_value)
{
    struct acpi_gpe_walk_info *gpe_info = (void *)info;
    struct acpi_namespace_node *gpe_device;
    struct acpi_gpe_block_info *gpe_block;
    struct acpi_namespace_node *target_gpe_device;
    struct acpi_gpe_event_info *gpe_event_info;
    union acpi_operand_object *pkg_desc;
    union acpi_operand_object *obj_desc;
    u32 gpe_number;
    acpi_status status;

    ACPI_FUNCTION_TRACE(ev_match_prw_and_gpe);

    /* Check for a _PRW method under this device */

    status = acpi_ut_evaluate_object(obj_handle, METHOD_NAME__PRW,
                     ACPI_BTYPE_PACKAGE, &pkg_desc);
    if (ACPI_FAILURE(status)) {

        /* Ignore all errors from _PRW, we don't want to abort the subsystem */

        return_ACPI_STATUS(AE_OK);
    }

    /* The returned _PRW package must have at least two elements */

    if (pkg_desc->package.count < 2) {
        goto cleanup;
    }

    /* Extract pointers from the input context */

    gpe_device = gpe_info->gpe_device;
    gpe_block = gpe_info->gpe_block;

    /*
     * The _PRW object must return a package, we are only interested
     * in the first element
     */
    obj_desc = pkg_desc->package.elements[0];

    if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) {

        /* Use FADT-defined GPE device (from definition of _PRW) */

        target_gpe_device = acpi_gbl_fadt_gpe_device;

        /* Integer is the GPE number in the FADT described GPE blocks */

        gpe_number = (u32) obj_desc->integer.value;
    } else if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_PACKAGE) {

        /* Package contains a GPE reference and GPE number within a GPE block */

        if ((obj_desc->package.count < 2) ||
            (ACPI_GET_OBJECT_TYPE(obj_desc->package.elements[0]) !=
             ACPI_TYPE_LOCAL_REFERENCE)
            || (ACPI_GET_OBJECT_TYPE(obj_desc->package.elements[1]) !=
            ACPI_TYPE_INTEGER)) {
            goto cleanup;
        }

        /* Get GPE block reference and decode */

        target_gpe_device =
            obj_desc->package.elements[0]->reference.node;
        gpe_number = (u32) obj_desc->package.elements[1]->integer.value;
    } else {
        /* Unknown type, just ignore it */

        goto cleanup;
    }

    /*
     * Is this GPE within this block?
     *
     * TRUE iff these conditions are true:
     *     1) The GPE devices match.
     *     2) The GPE index(number) is within the range of the Gpe Block
     *          associated with the GPE device.
     */
    if ((gpe_device == target_gpe_device) &&
        (gpe_number >= gpe_block->block_base_number) &&
        (gpe_number <
         gpe_block->block_base_number + (gpe_block->register_count * 8))) {
        gpe_event_info =
            &gpe_block->event_info[gpe_number -
                       gpe_block->block_base_number];

        /* Mark GPE for WAKE-ONLY but WAKE_DISABLED */

        gpe_event_info->flags &=
            ~(ACPI_GPE_WAKE_ENABLED | ACPI_GPE_RUN_ENABLED);

        status =
            acpi_ev_set_gpe_type(gpe_event_info, ACPI_GPE_TYPE_WAKE);
        if (ACPI_FAILURE(status)) {
            goto cleanup;
        }
        status =
            acpi_ev_update_gpe_enable_masks(gpe_event_info,
                            ACPI_GPE_DISABLE);
    }

      cleanup:
    acpi_ut_remove_reference(pkg_desc);
    return_ACPI_STATUS(AE_OK);
}
/*******************************************************************************
 *
 * 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);
}