예제 #1
0
acpi_status
acpi_install_gpe_handler (
	u32                     gpe_number,
	u32                     type,
	acpi_gpe_handler        handler,
	void                    *context)
{
	acpi_status             status = AE_OK;


	FUNCTION_TRACE ("Acpi_install_gpe_handler");


	/* Parameter validation */

	if (!handler || (gpe_number > ACPI_GPE_MAX)) {
		return_ACPI_STATUS (AE_BAD_PARAMETER);
	}

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

	if (acpi_gbl_gpe_valid[gpe_number] == ACPI_GPE_INVALID) {
		return_ACPI_STATUS (AE_BAD_PARAMETER);
	}

	acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);

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

	if (acpi_gbl_gpe_info[gpe_number].handler) {
		status = AE_EXIST;
		goto cleanup;
	}

	/* Install the handler */

	acpi_gbl_gpe_info[gpe_number].handler = handler;
	acpi_gbl_gpe_info[gpe_number].context = context;
	acpi_gbl_gpe_info[gpe_number].type = (u8) type;

	/* Clear the GPE (of stale events), the enable it */

	acpi_hw_clear_gpe (gpe_number);
	acpi_hw_enable_gpe (gpe_number);


cleanup:
	acpi_ut_release_mutex (ACPI_MTX_EVENTS);
	return_ACPI_STATUS (status);
}
예제 #2
0
acpi_status
acpi_remove_gpe_handler (
	u32                     gpe_number,
	acpi_gpe_handler        handler)
{
	acpi_status             status = AE_OK;


	FUNCTION_TRACE ("Acpi_remove_gpe_handler");


	/* Parameter validation */

	if (!handler || (gpe_number > ACPI_GPE_MAX)) {
		return_ACPI_STATUS (AE_BAD_PARAMETER);
	}

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

	if (acpi_gbl_gpe_valid[gpe_number] == ACPI_GPE_INVALID) {
		return_ACPI_STATUS (AE_BAD_PARAMETER);
	}

	/* Disable the GPE before removing the handler */

	acpi_hw_disable_gpe (gpe_number);

	acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);

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

	if (acpi_gbl_gpe_info[gpe_number].handler != handler) {
		acpi_hw_enable_gpe (gpe_number);
		status = AE_BAD_PARAMETER;
		goto cleanup;
	}

	/* Remove the handler */

	acpi_gbl_gpe_info[gpe_number].handler = NULL;
	acpi_gbl_gpe_info[gpe_number].context = NULL;


cleanup:
	acpi_ut_release_mutex (ACPI_MTX_EVENTS);
	return_ACPI_STATUS (status);
}
예제 #3
0
static void
acpi_ev_asynch_execute_gpe_method (
	void                    *context)
{
	unsigned long           gpe_number = (unsigned long) context;
	acpi_gpe_level_info     gpe_info;


	FUNCTION_TRACE ("Ev_asynch_execute_gpe_method");

	/*
	 * Take a snapshot of the GPE info for this level
	 */
	acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
	gpe_info = acpi_gbl_gpe_info [gpe_number];
	acpi_ut_release_mutex (ACPI_MTX_EVENTS);

	/*
	 * Method Handler (_Lxx, _Exx):
	 * ----------------------------
	 * Evaluate the _Lxx/_Exx control method that corresponds to this GPE.
	 */
	if (gpe_info.method_handle) {
		acpi_ns_evaluate_by_handle (gpe_info.method_handle, NULL, NULL);
	}

	/*
	 * Level-Triggered?
	 * ----------------
	 * If level-triggered we clear the GPE status bit after handling the event.
	 */
	if (gpe_info.type & ACPI_EVENT_LEVEL_TRIGGERED) {
		acpi_hw_clear_gpe (gpe_number);
	}

	/*
	 * Enable the GPE.
	 */
	acpi_hw_enable_gpe (gpe_number);

	return_VOID;
}
예제 #4
0
static acpi_status
acpi_ev_save_method_info (
	acpi_handle                     obj_handle,
	u32                             level,
	void                            *obj_desc,
	void                            **return_value)
{
	struct acpi_gpe_block_info      *gpe_block = (void *) obj_desc;
	struct acpi_gpe_event_info      *gpe_event_info;
	u32                             gpe_number;
	char                            name[ACPI_NAME_SIZE + 1];
	u8                              type;
	acpi_status                     status;


	ACPI_FUNCTION_TRACE ("ev_save_method_info");


	/* Extract the name from the object and convert to a string */

	ACPI_MOVE_32_TO_32 (name,
			   &((struct acpi_namespace_node *) obj_handle)->name.integer);
	name[ACPI_NAME_SIZE] = 0;

	/*
	 * Edge/Level determination is based on the 2nd character
	 * of the method name
	 */
	switch (name[1]) {
	case 'L':
		type = ACPI_EVENT_LEVEL_TRIGGERED;
		break;

	case 'E':
		type = ACPI_EVENT_EDGE_TRIGGERED;
		break;

	default:
		/* Unknown method type, just ignore it! */

		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
			"Unknown GPE method type: %s (name not of form _Lnn or _Enn)\n",
			name));
		return_ACPI_STATUS (AE_OK);
	}

	/* Convert the last two characters of the name to the GPE Number */

	gpe_number = ACPI_STRTOUL (&name[2], NULL, 16);
	if (gpe_number == ACPI_UINT32_MAX) {
		/* Conversion failed; invalid method, just ignore it */

		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
			"Could not extract GPE number from name: %s (name is not of form _Lnn or _Enn)\n",
			name));
		return_ACPI_STATUS (AE_OK);
	}

	/* Ensure that we have a valid GPE number for this GPE block */

	if ((gpe_number < gpe_block->block_base_number) ||
		(gpe_number >= (gpe_block->block_base_number + (gpe_block->register_count * 8)))) {
		/*
		 * Not valid for this GPE block, just ignore it
		 * However, it may be valid for a different GPE block, since GPE0 and GPE1
		 * methods both appear under \_GPE.
		 */
		return_ACPI_STATUS (AE_OK);
	}

	/*
	 * Now we can add this information to the gpe_event_info block
	 * for use during dispatch of this GPE.
	 */
	gpe_event_info = &gpe_block->event_info[gpe_number - gpe_block->block_base_number];

	gpe_event_info->flags    = type;
	gpe_event_info->method_node = (struct acpi_namespace_node *) obj_handle;

	/* Enable the GPE (SCIs should be disabled at this point) */

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

	ACPI_DEBUG_PRINT ((ACPI_DB_LOAD,
		"Registered GPE method %s as GPE number 0x%.2X\n",
		name, gpe_number));
	return_ACPI_STATUS (AE_OK);
}
예제 #5
0
파일: evgpe.c 프로젝트: dduval/kernel-rhel3
static void ACPI_SYSTEM_XFACE
acpi_ev_asynch_execute_gpe_method (
	void                            *context)
{
	struct acpi_gpe_event_info      *gpe_event_info = (void *) context;
	u32                             gpe_number = 0;
	acpi_status                     status;
	struct acpi_gpe_event_info      local_gpe_event_info;


	ACPI_FUNCTION_TRACE ("ev_asynch_execute_gpe_method");


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

	/* Must revalidate the gpe_number/gpe_block */

	if (!acpi_ev_valid_gpe_event (gpe_event_info)) {
		status = acpi_ut_release_mutex (ACPI_MTX_EVENTS);
		return_VOID;
	}

	/*
	 * Take a snapshot of the GPE info for this level - we copy the
	 * info to prevent a race condition with remove_handler/remove_block.
	 */
	ACPI_MEMCPY (&local_gpe_event_info, gpe_event_info, sizeof (struct acpi_gpe_event_info));

	status = acpi_ut_release_mutex (ACPI_MTX_EVENTS);
	if (ACPI_FAILURE (status)) {
		return_VOID;
	}

	if (local_gpe_event_info.method_node) {
		/*
		 * Invoke the GPE Method (_Lxx, _Exx):
		 * (Evaluate the _Lxx/_Exx control method that corresponds to this GPE.)
		 */
		status = acpi_ns_evaluate_by_handle (local_gpe_event_info.method_node, NULL, NULL);
		if (ACPI_FAILURE (status)) {
			ACPI_REPORT_ERROR (("%s while evaluating method [%4.4s] for GPE[%2X]\n",
				acpi_format_exception (status),
				local_gpe_event_info.method_node->name.ascii, gpe_number));
		}
	}

	if (local_gpe_event_info.flags & ACPI_EVENT_LEVEL_TRIGGERED) {
		/*
		 * GPE is level-triggered, we clear the GPE status bit after handling
		 * the event.
		 */
		status = acpi_hw_clear_gpe (&local_gpe_event_info);
		if (ACPI_FAILURE (status)) {
			return_VOID;
		}
	}

	/* Enable this GPE */

	(void) acpi_hw_enable_gpe (&local_gpe_event_info);
	return_VOID;
}
예제 #6
0
u32
acpi_ev_gpe_dispatch (
	u32                     gpe_number)
{
	acpi_gpe_level_info     gpe_info;


	FUNCTION_TRACE ("Ev_gpe_dispatch");


	/*
	 * Valid GPE number?
	 */
	if (acpi_gbl_gpe_valid[gpe_number] == ACPI_GPE_INVALID) {
		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid GPE bit [%X].\n", gpe_number));
		return_VALUE (INTERRUPT_NOT_HANDLED);
	}

	/*
	 * Disable the GPE.
	 */
	acpi_hw_disable_gpe (gpe_number);

	gpe_info = acpi_gbl_gpe_info [gpe_number];

	/*
	 * Edge-Triggered?
	 * ---------------
	 * If edge-triggered, clear the GPE status bit now.  Note that
	 * level-triggered events are cleared after the GPE is serviced.
	 */
	if (gpe_info.type & ACPI_EVENT_EDGE_TRIGGERED) {
		acpi_hw_clear_gpe (gpe_number);
	}
		/*
		 * Function Handler (e.g. EC)?
		 */
	if (gpe_info.handler) {
		/* Invoke function handler (at interrupt level). */

		gpe_info.handler (gpe_info.context);

		/* Level-Triggered? */

		if (gpe_info.type & ACPI_EVENT_LEVEL_TRIGGERED) {
			acpi_hw_clear_gpe (gpe_number);
		}

		/* Enable GPE */

		acpi_hw_enable_gpe (gpe_number);
	}

	/*
	 * Method Handler (e.g. _Exx/_Lxx)?
	 */
	else if (gpe_info.method_handle) {
		if (ACPI_FAILURE(acpi_os_queue_for_execution (OSD_PRIORITY_GPE,
			acpi_ev_asynch_execute_gpe_method, (void*) (u64)gpe_number))) {
			/*
			 * Shoudn't occur, but if it does report an error. Note that
			 * the GPE will remain disabled until the ACPI Core Subsystem
			 * is restarted, or the handler is removed/reinstalled.
			 */
			REPORT_ERROR (("Acpi_ev_gpe_dispatch: Unable to queue handler for GPE bit [%X]\n", gpe_number));
		}
	}

	/*
	 * No Handler? Report an error and leave the GPE disabled.
	 */
	else {
		REPORT_ERROR (("Acpi_ev_gpe_dispatch: No installed handler for GPE [%X]\n", gpe_number));

		/* Level-Triggered? */

		if (gpe_info.type & ACPI_EVENT_LEVEL_TRIGGERED) {
			acpi_hw_clear_gpe (gpe_number);
		}
	}

	return_VALUE (INTERRUPT_HANDLED);
}
예제 #7
0
static acpi_status
acpi_ev_save_method_info (
	acpi_handle             obj_handle,
	u32                     level,
	void                    *obj_desc,
	void                    **return_value)
{
	u32                     gpe_number;
	NATIVE_CHAR             name[ACPI_NAME_SIZE + 1];
	u8                      type;


	PROC_NAME ("Ev_save_method_info");


	/* Extract the name from the object and convert to a string */

	MOVE_UNALIGNED32_TO_32 (name, &((acpi_namespace_node *) obj_handle)->name);
	name[ACPI_NAME_SIZE] = 0;

	/*
	 * Edge/Level determination is based on the 2nd s8 of the method name
	 */
	if (name[1] == 'L') {
		type = ACPI_EVENT_LEVEL_TRIGGERED;
	}
	else if (name[1] == 'E') {
		type = ACPI_EVENT_EDGE_TRIGGERED;
	}
	else {
		/* Unknown method type, just ignore it! */

		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
			"Unknown GPE method type: %s (name not of form _Lnn or _Enn)\n",
			name));
		return (AE_OK);
	}

	/* Convert the last two characters of the name to the Gpe Number */

	gpe_number = STRTOUL (&name[2], NULL, 16);
	if (gpe_number == ACPI_UINT32_MAX) {
		/* Conversion failed; invalid method, just ignore it */

		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
			"Could not extract GPE number from name: %s (name not of form _Lnn or _Enn)\n",
			name));
		return (AE_OK);
	}

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

	if (acpi_gbl_gpe_valid[gpe_number] == ACPI_GPE_INVALID) {
		/* Not valid, all we can do here is ignore it */

		return (AE_OK);
	}

	/*
	 * Now we can add this information to the Gpe_info block
	 * for use during dispatch of this GPE.
	 */
	acpi_gbl_gpe_info [gpe_number].type         = type;
	acpi_gbl_gpe_info [gpe_number].method_handle = obj_handle;


	/*
	 * Enable the GPE (SCIs should be disabled at this point)
	 */
	acpi_hw_enable_gpe (gpe_number);

	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Registered GPE method %s as GPE number %X\n",
		name, gpe_number));
	return (AE_OK);
}