mirror of
https://github.com/reactos/reactos.git
synced 2024-09-20 01:31:34 +00:00
c501d8112c
svn path=/branches/aicom-network-fixes/; revision=34994
374 lines
9.3 KiB
C
374 lines
9.3 KiB
C
/******************************************************************************
|
|
*
|
|
* Module Name: evxfregn - External Interfaces, ACPI Operation Regions and
|
|
* Address Spaces.
|
|
* $Revision: 1.2 $
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/*
|
|
* 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>
|
|
|
|
#define _COMPONENT ACPI_EVENTS
|
|
MODULE_NAME ("evxfregn")
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION: Acpi_install_address_space_handler
|
|
*
|
|
* PARAMETERS: Device - Handle for the device
|
|
* Space_id - The address space ID
|
|
* Handler - Address of the handler
|
|
* Setup - Address of the setup function
|
|
* Context - Value passed to the handler on each access
|
|
*
|
|
* RETURN: Status
|
|
*
|
|
* DESCRIPTION: Install a handler for all Op_regions of a given Space_id.
|
|
*
|
|
******************************************************************************/
|
|
|
|
ACPI_STATUS
|
|
acpi_install_address_space_handler (
|
|
ACPI_HANDLE device,
|
|
ACPI_ADDRESS_SPACE_TYPE space_id,
|
|
ADDRESS_SPACE_HANDLER handler,
|
|
ADDRESS_SPACE_SETUP setup,
|
|
void *context)
|
|
{
|
|
ACPI_OPERAND_OBJECT *obj_desc;
|
|
ACPI_OPERAND_OBJECT *handler_obj;
|
|
ACPI_NAMESPACE_NODE *node;
|
|
ACPI_STATUS status = AE_OK;
|
|
OBJECT_TYPE_INTERNAL type;
|
|
u16 flags = 0;
|
|
|
|
|
|
/* Parameter validation */
|
|
|
|
if ((!device) ||
|
|
((!handler) && (handler != ACPI_DEFAULT_HANDLER))) {
|
|
return (AE_BAD_PARAMETER);
|
|
}
|
|
|
|
acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
|
|
|
|
/* Convert and validate the device handle */
|
|
|
|
node = acpi_ns_convert_handle_to_entry (device);
|
|
if (!node) {
|
|
status = AE_BAD_PARAMETER;
|
|
goto unlock_and_exit;
|
|
}
|
|
|
|
/*
|
|
* This registration is valid for only the types below
|
|
* and the root. This is where the default handlers
|
|
* get placed.
|
|
*/
|
|
|
|
if ((node->type != ACPI_TYPE_DEVICE) &&
|
|
(node->type != ACPI_TYPE_PROCESSOR) &&
|
|
(node->type != ACPI_TYPE_THERMAL) &&
|
|
(node != acpi_gbl_root_node)) {
|
|
status = AE_BAD_PARAMETER;
|
|
goto unlock_and_exit;
|
|
}
|
|
|
|
if (handler == ACPI_DEFAULT_HANDLER) {
|
|
flags = ADDR_HANDLER_DEFAULT_INSTALLED;
|
|
|
|
switch (space_id) {
|
|
case ADDRESS_SPACE_SYSTEM_MEMORY:
|
|
handler = acpi_aml_system_memory_space_handler;
|
|
setup = acpi_ev_system_memory_region_setup;
|
|
break;
|
|
|
|
case ADDRESS_SPACE_SYSTEM_IO:
|
|
handler = acpi_aml_system_io_space_handler;
|
|
setup = acpi_ev_io_space_region_setup;
|
|
break;
|
|
|
|
case ADDRESS_SPACE_PCI_CONFIG:
|
|
handler = acpi_aml_pci_config_space_handler;
|
|
setup = acpi_ev_pci_config_region_setup;
|
|
break;
|
|
|
|
default:
|
|
status = AE_NOT_EXIST;
|
|
goto unlock_and_exit;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If the caller hasn't specified a setup routine, use the default
|
|
*/
|
|
if (!setup) {
|
|
setup = acpi_ev_default_region_setup;
|
|
}
|
|
|
|
/*
|
|
* Check for an existing internal object
|
|
*/
|
|
|
|
obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) node);
|
|
if (obj_desc) {
|
|
/*
|
|
* The object exists.
|
|
* Make sure the handler is not already installed.
|
|
*/
|
|
|
|
/* check the address handler the user requested */
|
|
|
|
handler_obj = obj_desc->device.addr_handler;
|
|
while (handler_obj) {
|
|
/*
|
|
* We have an Address handler, see if user requested this
|
|
* address space.
|
|
*/
|
|
if(handler_obj->addr_handler.space_id == space_id) {
|
|
status = AE_EXIST;
|
|
goto unlock_and_exit;
|
|
}
|
|
|
|
/*
|
|
* Move through the linked list of handlers
|
|
*/
|
|
handler_obj = handler_obj->addr_handler.next;
|
|
}
|
|
}
|
|
|
|
else {
|
|
/* Obj_desc does not exist, create one */
|
|
|
|
if (node->type == ACPI_TYPE_ANY) {
|
|
type = ACPI_TYPE_DEVICE;
|
|
}
|
|
|
|
else {
|
|
type = node->type;
|
|
}
|
|
|
|
obj_desc = acpi_cm_create_internal_object (type);
|
|
if (!obj_desc) {
|
|
status = AE_NO_MEMORY;
|
|
goto unlock_and_exit;
|
|
}
|
|
|
|
/* Init new descriptor */
|
|
|
|
obj_desc->common.type = (u8) type;
|
|
|
|
/* Attach the new object to the Node */
|
|
|
|
status = acpi_ns_attach_object (node, obj_desc, (u8) type);
|
|
if (ACPI_FAILURE (status)) {
|
|
acpi_cm_remove_reference (obj_desc);
|
|
goto unlock_and_exit;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Now we can install the handler
|
|
*
|
|
* At this point we know that there is no existing handler.
|
|
* So, we just allocate the object for the handler and link it
|
|
* into the list.
|
|
*/
|
|
handler_obj = acpi_cm_create_internal_object (INTERNAL_TYPE_ADDRESS_HANDLER);
|
|
if (!handler_obj) {
|
|
status = AE_NO_MEMORY;
|
|
goto unlock_and_exit;
|
|
}
|
|
|
|
handler_obj->addr_handler.space_id = (u8) space_id;
|
|
handler_obj->addr_handler.hflags = flags;
|
|
handler_obj->addr_handler.next = obj_desc->device.addr_handler;
|
|
handler_obj->addr_handler.region_list = NULL;
|
|
handler_obj->addr_handler.node = node;
|
|
handler_obj->addr_handler.handler = handler;
|
|
handler_obj->addr_handler.context = context;
|
|
handler_obj->addr_handler.setup = setup;
|
|
|
|
/*
|
|
* Now walk the namespace finding all of the regions this
|
|
* handler will manage.
|
|
*
|
|
* We start at the device and search the branch toward
|
|
* the leaf nodes until either the leaf is encountered or
|
|
* a device is detected that has an address handler of the
|
|
* same type.
|
|
*
|
|
* In either case we back up and search down the remainder
|
|
* of the branch
|
|
*/
|
|
status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, device,
|
|
ACPI_UINT32_MAX, NS_WALK_UNLOCK,
|
|
acpi_ev_addr_handler_helper,
|
|
handler_obj, NULL);
|
|
|
|
/*
|
|
* Place this handler 1st on the list
|
|
*/
|
|
|
|
handler_obj->common.reference_count =
|
|
(u16) (handler_obj->common.reference_count +
|
|
obj_desc->common.reference_count - 1);
|
|
obj_desc->device.addr_handler = handler_obj;
|
|
|
|
|
|
unlock_and_exit:
|
|
acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
|
|
return (status);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION: Acpi_remove_address_space_handler
|
|
*
|
|
* PARAMETERS: Space_id - The address space ID
|
|
* Handler - Address of the handler
|
|
*
|
|
* RETURN: Status
|
|
*
|
|
* DESCRIPTION: Install a handler for accesses on an Operation Region
|
|
*
|
|
******************************************************************************/
|
|
|
|
ACPI_STATUS
|
|
acpi_remove_address_space_handler (
|
|
ACPI_HANDLE device,
|
|
ACPI_ADDRESS_SPACE_TYPE space_id,
|
|
ADDRESS_SPACE_HANDLER handler)
|
|
{
|
|
ACPI_OPERAND_OBJECT *obj_desc;
|
|
ACPI_OPERAND_OBJECT *handler_obj;
|
|
ACPI_OPERAND_OBJECT *region_obj;
|
|
ACPI_OPERAND_OBJECT **last_obj_ptr;
|
|
ACPI_NAMESPACE_NODE *node;
|
|
ACPI_STATUS status = AE_OK;
|
|
|
|
|
|
/* Parameter validation */
|
|
|
|
if ((!device) ||
|
|
((!handler) && (handler != ACPI_DEFAULT_HANDLER))) {
|
|
return (AE_BAD_PARAMETER);
|
|
}
|
|
|
|
acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
|
|
|
|
/* Convert and validate the device handle */
|
|
|
|
node = acpi_ns_convert_handle_to_entry (device);
|
|
if (!node) {
|
|
status = AE_BAD_PARAMETER;
|
|
goto unlock_and_exit;
|
|
}
|
|
|
|
|
|
/* Make sure the internal object exists */
|
|
|
|
obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) node);
|
|
if (!obj_desc) {
|
|
/*
|
|
* The object DNE.
|
|
*/
|
|
status = AE_NOT_EXIST;
|
|
goto unlock_and_exit;
|
|
}
|
|
|
|
/*
|
|
* find the address handler the user requested
|
|
*/
|
|
|
|
handler_obj = obj_desc->device.addr_handler;
|
|
last_obj_ptr = &obj_desc->device.addr_handler;
|
|
while (handler_obj) {
|
|
/*
|
|
* We have a handler, see if user requested this one
|
|
*/
|
|
|
|
if(handler_obj->addr_handler.space_id == space_id) {
|
|
/*
|
|
* Got it, first dereference this in the Regions
|
|
*/
|
|
region_obj = handler_obj->addr_handler.region_list;
|
|
|
|
/* Walk the handler's region list */
|
|
|
|
while (region_obj) {
|
|
/*
|
|
* First disassociate the handler from the region.
|
|
*
|
|
* NOTE: this doesn't mean that the region goes away
|
|
* The region is just inaccessible as indicated to
|
|
* the _REG method
|
|
*/
|
|
acpi_ev_disassociate_region_from_handler(region_obj, FALSE);
|
|
|
|
/*
|
|
* Walk the list, since we took the first region and it
|
|
* was removed from the list by the dissassociate call
|
|
* we just get the first item on the list again
|
|
*/
|
|
region_obj = handler_obj->addr_handler.region_list;
|
|
|
|
}
|
|
|
|
/*
|
|
* Remove this Handler object from the list
|
|
*/
|
|
*last_obj_ptr = handler_obj->addr_handler.next;
|
|
|
|
/*
|
|
* Now we can delete the handler object
|
|
*/
|
|
acpi_cm_remove_reference (handler_obj);
|
|
acpi_cm_remove_reference (handler_obj);
|
|
|
|
goto unlock_and_exit;
|
|
}
|
|
|
|
/*
|
|
* Move through the linked list of handlers
|
|
*/
|
|
last_obj_ptr = &handler_obj->addr_handler.next;
|
|
handler_obj = handler_obj->addr_handler.next;
|
|
}
|
|
|
|
|
|
/*
|
|
* The handler does not exist
|
|
*/
|
|
status = AE_NOT_EXIST;
|
|
|
|
|
|
unlock_and_exit:
|
|
acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
|
|
return (status);
|
|
}
|
|
|
|
|