📄 evevent.c
字号:
/****************************************************************************** * * Module Name: evevent - Fixed and General Purpose Acpi_event * handling and dispatch * $Revision: 51 $ * *****************************************************************************//* * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include "acpi.h"#include "achware.h"#include "acevents.h"#include "acnamesp.h"#define _COMPONENT ACPI_EVENTS MODULE_NAME ("evevent")/******************************************************************************* * * FUNCTION: Acpi_ev_initialize * * PARAMETERS: None * * RETURN: Status * * DESCRIPTION: Ensures that the system control interrupt (SCI) is properly * configured, disables SCI event sources, installs the SCI * handler * ******************************************************************************/acpi_statusacpi_ev_initialize ( void){ acpi_status status; FUNCTION_TRACE ("Ev_initialize"); /* Make sure we have ACPI tables */ if (!acpi_gbl_DSDT) { ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "No ACPI tables present!\n")); return_ACPI_STATUS (AE_NO_ACPI_TABLES); } /* Make sure the BIOS supports ACPI mode */ if (SYS_MODE_LEGACY == acpi_hw_get_mode_capabilities()) { ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "ACPI Mode is not supported!\n")); return_ACPI_STATUS (AE_ERROR); } acpi_gbl_original_mode = acpi_hw_get_mode(); /* * Initialize the Fixed and General Purpose Acpi_events prior. This is * done prior to enabling SCIs to prevent interrupts from occuring * before handers are installed. */ status = acpi_ev_fixed_event_initialize (); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, "Unable to initialize fixed events.\n")); return_ACPI_STATUS (status); } status = acpi_ev_gpe_initialize (); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, "Unable to initialize general purpose events.\n")); return_ACPI_STATUS (status); } /* Install the SCI handler */ status = acpi_ev_install_sci_handler (); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, "Unable to install System Control Interrupt Handler\n")); return_ACPI_STATUS (status); } /* Install handlers for control method GPE handlers (_Lxx, _Exx) */ status = acpi_ev_init_gpe_control_methods (); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, "Unable to initialize Gpe control methods\n")); return_ACPI_STATUS (status); } /* Install the handler for the Global Lock */ status = acpi_ev_init_global_lock_handler (); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, "Unable to initialize Global Lock handler\n")); return_ACPI_STATUS (status); } return_ACPI_STATUS (status);}/******************************************************************************* * * FUNCTION: Acpi_ev_fixed_event_initialize * * PARAMETERS: None * * RETURN: Status * * DESCRIPTION: Initialize the Fixed Acpi_event data structures * ******************************************************************************/acpi_statusacpi_ev_fixed_event_initialize(void){ int i = 0; /* Initialize the structure that keeps track of fixed event handlers */ for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { acpi_gbl_fixed_event_handlers[i].handler = NULL; acpi_gbl_fixed_event_handlers[i].context = NULL; } acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK, TMR_EN, 0); acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK, GBL_EN, 0); acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK, PWRBTN_EN, 0); acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK, SLPBTN_EN, 0); acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK, RTC_EN, 0); return (AE_OK);}/******************************************************************************* * * FUNCTION: Acpi_ev_fixed_event_detect * * PARAMETERS: None * * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED * * DESCRIPTION: Checks the PM status register for fixed events * ******************************************************************************/u32acpi_ev_fixed_event_detect (void){ u32 int_status = INTERRUPT_NOT_HANDLED; u32 status_register; u32 enable_register; PROC_NAME ("Ev_fixed_event_detect"); /* * Read the fixed feature status and enable registers, as all the cases * depend on their values. */ status_register = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, PM1_STS); enable_register = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, PM1_EN); ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS, "Fixed Acpi_event Block: Enable %08X Status %08X\n", enable_register, status_register)); /* power management timer roll over */ if ((status_register & ACPI_STATUS_PMTIMER) && (enable_register & ACPI_ENABLE_PMTIMER)) { int_status |= acpi_ev_fixed_event_dispatch (ACPI_EVENT_PMTIMER); } /* global event (BIOS wants the global lock) */ if ((status_register & ACPI_STATUS_GLOBAL) && (enable_register & ACPI_ENABLE_GLOBAL)) { int_status |= acpi_ev_fixed_event_dispatch (ACPI_EVENT_GLOBAL); } /* power button event */ if ((status_register & ACPI_STATUS_POWER_BUTTON) && (enable_register & ACPI_ENABLE_POWER_BUTTON)) { int_status |= acpi_ev_fixed_event_dispatch (ACPI_EVENT_POWER_BUTTON); } /* sleep button event */ if ((status_register & ACPI_STATUS_SLEEP_BUTTON) && (enable_register & ACPI_ENABLE_SLEEP_BUTTON)) { int_status |= acpi_ev_fixed_event_dispatch (ACPI_EVENT_SLEEP_BUTTON); } return (int_status);}/******************************************************************************* * * FUNCTION: Acpi_ev_fixed_event_dispatch * * PARAMETERS: Event - Event type * * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED * * DESCRIPTION: Clears the status bit for the requested event, calls the * handler that previously registered for the event. * ******************************************************************************/u32acpi_ev_fixed_event_dispatch ( u32 event){ u32 register_id; FUNCTION_ENTRY (); /* Clear the status bit */ switch (event) { case ACPI_EVENT_PMTIMER: register_id = TMR_STS; break; case ACPI_EVENT_GLOBAL: register_id = GBL_STS; break; case ACPI_EVENT_POWER_BUTTON: register_id = PWRBTN_STS; break; case ACPI_EVENT_SLEEP_BUTTON: register_id = SLPBTN_STS; break; case ACPI_EVENT_RTC: register_id = RTC_STS; break; default: return 0; break; } acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_DO_NOT_LOCK, register_id, 1); /* * Make sure we've got a handler. If not, report an error. * The event is disabled to prevent further interrupts. */ if (NULL == acpi_gbl_fixed_event_handlers[event].handler) { register_id = (PM1_EN | REGISTER_BIT_ID(register_id)); acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_DO_NOT_LOCK, register_id, 0); REPORT_ERROR ( ("Ev_gpe_dispatch: No installed handler for fixed event [%08X]\n", event)); return (INTERRUPT_NOT_HANDLED); } /* Invoke the handler */ return ((acpi_gbl_fixed_event_handlers[event].handler)( acpi_gbl_fixed_event_handlers[event].context));}/******************************************************************************* * * FUNCTION: Acpi_ev_gpe_initialize * * PARAMETERS: None * * RETURN: Status * * DESCRIPTION: Initialize the GPE data structures * ******************************************************************************/acpi_statusacpi_ev_gpe_initialize (void){ u32 i; u32 j; u32 register_index; u32 gpe_number; u16 gpe0register_count; u16 gpe1_register_count; FUNCTION_TRACE ("Ev_gpe_initialize"); /* * Set up various GPE counts * * You may ask,why are the GPE register block lengths divided by 2? * From the ACPI 2.0 Spec, section, 4.7.1.6 General-Purpose Event * Registers, we have, * * "Each register block contains two registers of equal length * GPEx_STS and GPEx_EN (where x is 0 or 1). The length of the * GPE0_STS and GPE0_EN registers is equal to half the GPE0_LEN * The length of the GPE1_STS and GPE1_EN registers is equal to * half the GPE1_LEN. If a generic register block is not supported * then its respective block pointer and block length values in the * FADT table contain zeros. The GPE0_LEN and GPE1_LEN do not need * to be the same size." */ gpe0register_count = (u16) DIV_2 (acpi_gbl_FADT->gpe0blk_len); gpe1_register_count = (u16) DIV_2 (acpi_gbl_FADT->gpe1_blk_len); acpi_gbl_gpe_register_count = gpe0register_count + gpe1_register_count; if (!acpi_gbl_gpe_register_count) { REPORT_WARNING (("Zero GPEs are defined in the FADT\n")); return_ACPI_STATUS (AE_OK); } /* * Allocate the Gpe information block */ acpi_gbl_gpe_registers = ACPI_MEM_CALLOCATE (acpi_gbl_gpe_register_count * sizeof (acpi_gpe_registers)); if (!acpi_gbl_gpe_registers) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not allocate the Gpe_registers block\n")); return_ACPI_STATUS (AE_NO_MEMORY); } /* * Allocate the Gpe dispatch handler block * There are eight distinct GP events per register. * Initialization to zeros is sufficient */ acpi_gbl_gpe_info = ACPI_MEM_CALLOCATE (MUL_8 (acpi_gbl_gpe_register_count) * sizeof (acpi_gpe_level_info)); if (!acpi_gbl_gpe_info) { ACPI_MEM_FREE (acpi_gbl_gpe_registers); ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not allocate the Gpe_info block\n")); return_ACPI_STATUS (AE_NO_MEMORY); } /* Set the Gpe validation table to GPE_INVALID */ MEMSET (acpi_gbl_gpe_valid, (int) ACPI_GPE_INVALID, ACPI_NUM_GPE); /* * Initialize the Gpe information and validation blocks. A goal of these * blocks is to hide the fact that there are two separate GPE register sets * In a given block, the status registers occupy the first half, and * the enable registers occupy the second half. */ /* GPE Block 0 */ register_index = 0; for (i = 0; i < gpe0register_count; i++) { acpi_gbl_gpe_registers[register_index].status_addr = (u16) (ACPI_GET_ADDRESS (acpi_gbl_FADT->Xgpe0blk.address) + i); acpi_gbl_gpe_registers[register_index].enable_addr = (u16) (ACPI_GET_ADDRESS (acpi_gbl_FADT->Xgpe0blk.address) + i + gpe0register_count); acpi_gbl_gpe_registers[register_index].gpe_base = (u8) 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_write_port (acpi_gbl_gpe_registers[register_index].enable_addr, 0x00, 8); acpi_os_write_port (acpi_gbl_gpe_registers[register_index].status_addr, 0xFF, 8); register_index++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -