📄 evevent.c
字号:
* by writing a '0'.
*/
acpi_os_out8 (acpi_gbl_gpe_registers[register_index].enable_addr, 0x00);
acpi_os_out8 (acpi_gbl_gpe_registers[register_index].status_addr, 0xFF);
register_index++;
}
/* GPE Block 1 */
for (i = 0; i < gpe1_register_count; i++) {
acpi_gbl_gpe_registers[register_index].status_addr =
(u16) (ACPI_GET_ADDRESS (acpi_gbl_FADT->Xgpe1_blk.address) + i);
acpi_gbl_gpe_registers[register_index].enable_addr =
(u16) (ACPI_GET_ADDRESS (acpi_gbl_FADT->Xgpe1_blk.address) + i + gpe1_register_count);
acpi_gbl_gpe_registers[register_index].gpe_base =
(u8) (acpi_gbl_FADT->gpe1_base + MUL_8 (i));
for (j = 0; j < 8; j++) {
gpe_number = acpi_gbl_gpe_registers[register_index].gpe_base + j;
acpi_gbl_gpe_valid[gpe_number] = (u8) register_index;
}
/*
* Clear the status/enable registers. Note that status registers
* are cleared by writing a '1', while enable registers are cleared
* by writing a '0'.
*/
acpi_os_out8 (acpi_gbl_gpe_registers[register_index].enable_addr, 0x00);
acpi_os_out8 (acpi_gbl_gpe_registers[register_index].status_addr, 0xFF);
register_index++;
}
return (AE_OK);
}
/******************************************************************************
*
* FUNCTION: Acpi_ev_save_method_info
*
* PARAMETERS: None
*
* RETURN: None
*
* DESCRIPTION: Called from Acpi_walk_namespace. Expects each object to be a
* control method under the _GPE portion of the namespace.
* Extract the name and GPE type from the object, saving this
* information for quick lookup during GPE dispatch
*
* The name of each GPE control method is of the form:
* "_Lnn" or "_Enn"
* Where:
* L - means that the GPE is level triggered
* E - means that the GPE is edge triggered
* nn - is the GPE number
*
******************************************************************************/
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;
/* 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! */
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 */
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);
return (AE_OK);
}
/******************************************************************************
*
* FUNCTION: Acpi_ev_init_gpe_control_methods
*
* PARAMETERS: None
*
* RETURN: None
*
* DESCRIPTION: Obtain the control methods associated with the GPEs.
*
* NOTE: Must be called AFTER namespace initialization!
*
******************************************************************************/
ACPI_STATUS
acpi_ev_init_gpe_control_methods (void)
{
ACPI_STATUS status;
/* Get a permanent handle to the _GPE object */
status = acpi_get_handle (NULL, "\\_GPE", &acpi_gbl_gpe_obj_handle);
if (ACPI_FAILURE (status)) {
return (status);
}
/* Traverse the namespace under \_GPE to find all methods there */
status = acpi_walk_namespace (ACPI_TYPE_METHOD, acpi_gbl_gpe_obj_handle,
ACPI_UINT32_MAX, acpi_ev_save_method_info,
NULL, NULL);
return (status);
}
/******************************************************************************
*
* FUNCTION: Acpi_ev_gpe_detect
*
* PARAMETERS: None
*
* RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
*
* DESCRIPTION: Detect if any GP events have occurred
*
******************************************************************************/
u32
acpi_ev_gpe_detect (void)
{
u32 int_status = INTERRUPT_NOT_HANDLED;
u32 i;
u32 j;
u8 enabled_status_byte;
u8 bit_mask;
/*
* Read all of the 8-bit GPE status and enable registers
* in both of the register blocks, saving all of it.
* Find all currently active GP events.
*/
for (i = 0; i < acpi_gbl_gpe_register_count; i++) {
acpi_gbl_gpe_registers[i].status =
acpi_os_in8 (acpi_gbl_gpe_registers[i].status_addr);
acpi_gbl_gpe_registers[i].enable =
acpi_os_in8 (acpi_gbl_gpe_registers[i].enable_addr);
/* First check if there is anything active at all in this register */
enabled_status_byte = (u8) (acpi_gbl_gpe_registers[i].status &
acpi_gbl_gpe_registers[i].enable);
if (!enabled_status_byte) {
/* No active GPEs in this register, move on */
continue;
}
/* Now look at the individual GPEs in this byte register */
for (j = 0, bit_mask = 1; j < 8; j++, bit_mask <<= 1) {
/* Examine one GPE bit */
if (enabled_status_byte & bit_mask) {
/*
* Found an active GPE. Dispatch the event to a handler
* or method.
*/
int_status |=
acpi_ev_gpe_dispatch (acpi_gbl_gpe_registers[i].gpe_base + j);
}
}
}
return (int_status);
}
/******************************************************************************
*
* FUNCTION: Acpi_ev_asynch_execute_gpe_method
*
* PARAMETERS: Gpe_number - The 0-based Gpe number
*
* RETURN: None
*
* DESCRIPTION: Perform the actual execution of a GPE control method. This
* function is called from an invocation of Acpi_os_queue_for_execution
* (and therefore does NOT execute at interrupt level) so that
* the control method itself is not executed in the context of
* the SCI interrupt handler.
*
******************************************************************************/
static void
acpi_ev_asynch_execute_gpe_method (
void *context)
{
u32 gpe_number = (u32) context;
ACPI_GPE_LEVEL_INFO gpe_info;
/*
* Take a snapshot of the GPE info for this level
*/
acpi_cm_acquire_mutex (ACPI_MTX_EVENTS);
gpe_info = acpi_gbl_gpe_info [gpe_number];
acpi_cm_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;
}
/******************************************************************************
*
* FUNCTION: Acpi_ev_gpe_dispatch
*
* PARAMETERS: Gpe_number - The 0-based Gpe number
*
* RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
*
* DESCRIPTION: Handle and dispatch a General Purpose Acpi_event.
* Clears the status bit for the requested event.
*
* TBD: [Investigate] is this still valid or necessary:
* The Gpe handler differs from the fixed events in that it clears the enable
* bit rather than the status bit to clear the interrupt. This allows
* software outside of interrupt context to determine what caused the SCI and
* dispatch the correct AML.
*
******************************************************************************/
u32
acpi_ev_gpe_dispatch (
u32 gpe_number)
{
ACPI_GPE_LEVEL_INFO gpe_info;
/*
* Valid GPE number?
*/
if (acpi_gbl_gpe_valid[gpe_number] == ACPI_GPE_INVALID) {
return (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*)(NATIVE_UINT)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 (INTERRUPT_HANDLED);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -