diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-17 02:20:36 +0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-17 02:20:36 +0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/acpi/utilities | |
download | linux-1da177e4c3f41524e886b7f1b8a0c1fc7321cac2.tar.xz |
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/acpi/utilities')
-rw-r--r-- | drivers/acpi/utilities/Makefile | 8 | ||||
-rw-r--r-- | drivers/acpi/utilities/utalloc.c | 988 | ||||
-rw-r--r-- | drivers/acpi/utilities/utcopy.c | 930 | ||||
-rw-r--r-- | drivers/acpi/utilities/utdebug.c | 624 | ||||
-rw-r--r-- | drivers/acpi/utilities/utdelete.c | 700 | ||||
-rw-r--r-- | drivers/acpi/utilities/uteval.c | 696 | ||||
-rw-r--r-- | drivers/acpi/utilities/utglobal.c | 935 | ||||
-rw-r--r-- | drivers/acpi/utilities/utinit.c | 266 | ||||
-rw-r--r-- | drivers/acpi/utilities/utmath.c | 333 | ||||
-rw-r--r-- | drivers/acpi/utilities/utmisc.c | 1516 | ||||
-rw-r--r-- | drivers/acpi/utilities/utobject.c | 671 | ||||
-rw-r--r-- | drivers/acpi/utilities/utxface.c | 525 |
12 files changed, 8192 insertions, 0 deletions
diff --git a/drivers/acpi/utilities/Makefile b/drivers/acpi/utilities/Makefile new file mode 100644 index 000000000000..939c447dd52a --- /dev/null +++ b/drivers/acpi/utilities/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for all Linux ACPI interpreter subdirectories +# + +obj-y := utalloc.o utdebug.o uteval.o utinit.o utmisc.o utxface.o \ + utcopy.o utdelete.o utglobal.o utmath.o utobject.o + +EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c new file mode 100644 index 000000000000..3313439c4bc7 --- /dev/null +++ b/drivers/acpi/utilities/utalloc.c @@ -0,0 +1,988 @@ +/****************************************************************************** + * + * Module Name: utalloc - local cache and memory allocation routines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + + +#include <acpi/acpi.h> + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utalloc") + + +/****************************************************************************** + * + * FUNCTION: acpi_ut_release_to_cache + * + * PARAMETERS: list_id - Memory list/cache ID + * Object - The object to be released + * + * RETURN: None + * + * DESCRIPTION: Release an object to the specified cache. If cache is full, + * the object is deleted. + * + ******************************************************************************/ + +void +acpi_ut_release_to_cache ( + u32 list_id, + void *object) +{ + struct acpi_memory_list *cache_info; + + + ACPI_FUNCTION_ENTRY (); + + + cache_info = &acpi_gbl_memory_lists[list_id]; + +#ifdef ACPI_ENABLE_OBJECT_CACHE + + /* If walk cache is full, just free this wallkstate object */ + + if (cache_info->cache_depth >= cache_info->max_cache_depth) { + ACPI_MEM_FREE (object); + ACPI_MEM_TRACKING (cache_info->total_freed++); + } + + /* Otherwise put this object back into the cache */ + + else { + if (ACPI_FAILURE (acpi_ut_acquire_mutex (ACPI_MTX_CACHES))) { + return; + } + + /* Mark the object as cached */ + + ACPI_MEMSET (object, 0xCA, cache_info->object_size); + ACPI_SET_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_CACHED); + + /* Put the object at the head of the cache list */ + + * (ACPI_CAST_INDIRECT_PTR (char, &(((char *) object)[cache_info->link_offset]))) = cache_info->list_head; + cache_info->list_head = object; + cache_info->cache_depth++; + + (void) acpi_ut_release_mutex (ACPI_MTX_CACHES); + } + +#else + + /* Object cache is disabled; just free the object */ + + ACPI_MEM_FREE (object); + ACPI_MEM_TRACKING (cache_info->total_freed++); +#endif +} + + +/****************************************************************************** + * + * FUNCTION: acpi_ut_acquire_from_cache + * + * PARAMETERS: list_id - Memory list ID + * + * RETURN: A requested object. NULL if the object could not be + * allocated. + * + * DESCRIPTION: Get an object from the specified cache. If cache is empty, + * the object is allocated. + * + ******************************************************************************/ + +void * +acpi_ut_acquire_from_cache ( + u32 list_id) +{ + struct acpi_memory_list *cache_info; + void *object; + + + ACPI_FUNCTION_NAME ("ut_acquire_from_cache"); + + + cache_info = &acpi_gbl_memory_lists[list_id]; + +#ifdef ACPI_ENABLE_OBJECT_CACHE + + if (ACPI_FAILURE (acpi_ut_acquire_mutex (ACPI_MTX_CACHES))) { + return (NULL); + } + + ACPI_MEM_TRACKING (cache_info->cache_requests++); + + /* Check the cache first */ + + if (cache_info->list_head) { + /* There is an object available, use it */ + + object = cache_info->list_head; + cache_info->list_head = *(ACPI_CAST_INDIRECT_PTR (char, &(((char *) object)[cache_info->link_offset]))); + + ACPI_MEM_TRACKING (cache_info->cache_hits++); + cache_info->cache_depth--; + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Object %p from %s\n", + object, acpi_gbl_memory_lists[list_id].list_name)); +#endif + + if (ACPI_FAILURE (acpi_ut_release_mutex (ACPI_MTX_CACHES))) { + return (NULL); + } + + /* Clear (zero) the previously used Object */ + + ACPI_MEMSET (object, 0, cache_info->object_size); + } + + else { + /* The cache is empty, create a new object */ + + /* Avoid deadlock with ACPI_MEM_CALLOCATE */ + + if (ACPI_FAILURE (acpi_ut_release_mutex (ACPI_MTX_CACHES))) { + return (NULL); + } + + object = ACPI_MEM_CALLOCATE (cache_info->object_size); + ACPI_MEM_TRACKING (cache_info->total_allocated++); + } + +#else + + /* Object cache is disabled; just allocate the object */ + + object = ACPI_MEM_CALLOCATE (cache_info->object_size); + ACPI_MEM_TRACKING (cache_info->total_allocated++); +#endif + + return (object); +} + + +#ifdef ACPI_ENABLE_OBJECT_CACHE +/****************************************************************************** + * + * FUNCTION: acpi_ut_delete_generic_cache + * + * PARAMETERS: list_id - Memory list ID + * + * RETURN: None + * + * DESCRIPTION: Free all objects within the requested cache. + * + ******************************************************************************/ + +void +acpi_ut_delete_generic_cache ( + u32 list_id) +{ + struct acpi_memory_list *cache_info; + char *next; + + + ACPI_FUNCTION_ENTRY (); + + + cache_info = &acpi_gbl_memory_lists[list_id]; + while (cache_info->list_head) { + /* Delete one cached state object */ + + next = *(ACPI_CAST_INDIRECT_PTR (char, &(((char *) cache_info->list_head)[cache_info->link_offset]))); + ACPI_MEM_FREE (cache_info->list_head); + + cache_info->list_head = next; + cache_info->cache_depth--; + } +} +#endif + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_validate_buffer + * + * PARAMETERS: Buffer - Buffer descriptor to be validated + * + * RETURN: Status + * + * DESCRIPTION: Perform parameter validation checks on an struct acpi_buffer + * + ******************************************************************************/ + +acpi_status +acpi_ut_validate_buffer ( + struct acpi_buffer *buffer) +{ + + /* Obviously, the structure pointer must be valid */ + + if (!buffer) { + return (AE_BAD_PARAMETER); + } + + /* Special semantics for the length */ + + if ((buffer->length == ACPI_NO_BUFFER) || + (buffer->length == ACPI_ALLOCATE_BUFFER) || + (buffer->length == ACPI_ALLOCATE_LOCAL_BUFFER)) { + return (AE_OK); + } + + /* Length is valid, the buffer pointer must be also */ + + if (!buffer->pointer) { + return (AE_BAD_PARAMETER); + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_initialize_buffer + * + * PARAMETERS: Buffer - Buffer to be validated + * required_length - Length needed + * + * RETURN: Status + * + * DESCRIPTION: Validate that the buffer is of the required length or + * allocate a new buffer. Returned buffer is always zeroed. + * + ******************************************************************************/ + +acpi_status +acpi_ut_initialize_buffer ( + struct acpi_buffer *buffer, + acpi_size required_length) +{ + acpi_status status = AE_OK; + + + switch (buffer->length) { + case ACPI_NO_BUFFER: + + /* Set the exception and returned the required length */ + + status = AE_BUFFER_OVERFLOW; + break; + + + case ACPI_ALLOCATE_BUFFER: + + /* Allocate a new buffer */ + + buffer->pointer = acpi_os_allocate (required_length); + if (!buffer->pointer) { + return (AE_NO_MEMORY); + } + + /* Clear the buffer */ + + ACPI_MEMSET (buffer->pointer, 0, required_length); + break; + + + case ACPI_ALLOCATE_LOCAL_BUFFER: + + /* Allocate a new buffer with local interface to allow tracking */ + + buffer->pointer = ACPI_MEM_CALLOCATE (required_length); + if (!buffer->pointer) { + return (AE_NO_MEMORY); + } + break; + + + default: + + /* Existing buffer: Validate the size of the buffer */ + + if (buffer->length < required_length) { + status = AE_BUFFER_OVERFLOW; + break; + } + + /* Clear the buffer */ + + ACPI_MEMSET (buffer->pointer, 0, required_length); + break; + } + + buffer->length = required_length; + return (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_allocate + * + * PARAMETERS: Size - Size of the allocation + * Component - Component type of caller + * Module - Source file name of caller + * Line - Line number of caller + * + * RETURN: Address of the allocated memory on success, NULL on failure. + * + * DESCRIPTION: The subsystem's equivalent of malloc. + * + ******************************************************************************/ + +void * +acpi_ut_allocate ( + acpi_size size, + u32 component, + char *module, + u32 line) +{ + void *allocation; + + + ACPI_FUNCTION_TRACE_U32 ("ut_allocate", size); + + + /* Check for an inadvertent size of zero bytes */ + + if (!size) { + _ACPI_REPORT_ERROR (module, line, component, + ("ut_allocate: Attempt to allocate zero bytes\n")); + size = 1; + } + + allocation = acpi_os_allocate (size); + if (!allocation) { + /* Report allocation error */ + + _ACPI_REPORT_ERROR (module, line, component, + ("ut_allocate: Could not allocate size %X\n", (u32) size)); + + return_PTR (NULL); + } + + return_PTR (allocation); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_callocate + * + * PARAMETERS: Size - Size of the allocation + * Component - Component type of caller + * Module - Source file name of caller + * Line - Line number of caller + * + * RETURN: Address of the allocated memory on success, NULL on failure. + * + * DESCRIPTION: Subsystem equivalent of calloc. + * + ******************************************************************************/ + +void * +acpi_ut_callocate ( + acpi_size size, + u32 component, + char *module, + u32 line) +{ + void *allocation; + + + ACPI_FUNCTION_TRACE_U32 ("ut_callocate", size); + + + /* Check for an inadvertent size of zero bytes */ + + if (!size) { + _ACPI_REPORT_ERROR (module, line, component, + ("ut_callocate: Attempt to allocate zero bytes\n")); + return_PTR (NULL); + } + + allocation = acpi_os_allocate (size); + if (!allocation) { + /* Report allocation error */ + + _ACPI_REPORT_ERROR (module, line, component, + ("ut_callocate: Could not allocate size %X\n", (u32) size)); + return_PTR (NULL); + } + + /* Clear the memory block */ + + ACPI_MEMSET (allocation, 0, size); + return_PTR (allocation); +} + + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS +/* + * These procedures are used for tracking memory leaks in the subsystem, and + * they get compiled out when the ACPI_DBG_TRACK_ALLOCATIONS is not set. + * + * Each memory allocation is tracked via a doubly linked list. Each + * element contains the caller's component, module name, function name, and + * line number. acpi_ut_allocate and acpi_ut_callocate call + * acpi_ut_track_allocation to add an element to the list; deletion + * occurs in the body of acpi_ut_free. + */ + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_allocate_and_track + * + * PARAMETERS: Size - Size of the allocation + * Component - Component type of caller + * Module - Source file name of caller + * Line - Line number of caller + * + * RETURN: Address of the allocated memory on success, NULL on failure. + * + * DESCRIPTION: The subsystem's equivalent of malloc. + * + ******************************************************************************/ + +void * +acpi_ut_allocate_and_track ( + acpi_size size, + u32 component, + char *module, + u32 line) +{ + struct acpi_debug_mem_block *allocation; + acpi_status status; + + + allocation = acpi_ut_allocate (size + sizeof (struct acpi_debug_mem_header), component, + module, line); + if (!allocation) { + return (NULL); + } + + status = acpi_ut_track_allocation (ACPI_MEM_LIST_GLOBAL, allocation, size, + ACPI_MEM_MALLOC, component, module, line); + if (ACPI_FAILURE (status)) { + acpi_os_free (allocation); + return (NULL); + } + + acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].total_allocated++; + acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].current_total_size += (u32) size; + + return ((void *) &allocation->user_space); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_callocate_and_track + * + * PARAMETERS: Size - Size of the allocation + * Component - Component type of caller + * Module - Source file name of caller + * Line - Line number of caller + * + * RETURN: Address of the allocated memory on success, NULL on failure. + * + * DESCRIPTION: Subsystem equivalent of calloc. + * + ******************************************************************************/ + +void * +acpi_ut_callocate_and_track ( + acpi_size size, + u32 component, + char *module, + u32 line) +{ + struct acpi_debug_mem_block *allocation; + acpi_status status; + + + allocation = acpi_ut_callocate (size + sizeof (struct acpi_debug_mem_header), component, + module, line); + if (!allocation) { + /* Report allocation error */ + + _ACPI_REPORT_ERROR (module, line, component, + ("ut_callocate: Could not allocate size %X\n", (u32) size)); + return (NULL); + } + + status = acpi_ut_track_allocation (ACPI_MEM_LIST_GLOBAL, allocation, size, + ACPI_MEM_CALLOC, component, module, line); + if (ACPI_FAILURE (status)) { + acpi_os_free (allocation); + return (NULL); + } + + acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].total_allocated++; + acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].current_total_size += (u32) size; + + return ((void *) &allocation->user_space); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_free_and_track + * + * PARAMETERS: Allocation - Address of the memory to deallocate + * Component - Component type of caller + * Module - Source file name of caller + * Line - Line number of caller + * + * RETURN: None + * + * DESCRIPTION: Frees the memory at Allocation + * + ******************************************************************************/ + +void +acpi_ut_free_and_track ( + void *allocation, + u32 component, + char *module, + u32 line) +{ + struct acpi_debug_mem_block *debug_block; + acpi_status status; + + + ACPI_FUNCTION_TRACE_PTR ("ut_free", allocation); + + + if (NULL == allocation) { + _ACPI_REPORT_ERROR (module, line, component, + ("acpi_ut_free: Attempt to delete a NULL address\n")); + + return_VOID; + } + + debug_block = ACPI_CAST_PTR (struct acpi_debug_mem_block, + (((char *) allocation) - sizeof (struct acpi_debug_mem_header))); + + acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].total_freed++; + acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].current_total_size -= debug_block->size; + + status = acpi_ut_remove_allocation (ACPI_MEM_LIST_GLOBAL, debug_block, + component, module, line); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not free memory, %s\n", + acpi_format_exception (status))); + } + + acpi_os_free (debug_block); + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "%p freed\n", allocation)); + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_find_allocation + * + * PARAMETERS: list_id - Memory list to search + * Allocation - Address of allocated memory + * + * RETURN: A list element if found; NULL otherwise. + * + * DESCRIPTION: Searches for an element in the global allocation tracking list. + * + ******************************************************************************/ + +struct acpi_debug_mem_block * +acpi_ut_find_allocation ( + u32 list_id, + void *allocation) +{ + struct acpi_debug_mem_block *element; + + + ACPI_FUNCTION_ENTRY (); + + + if (list_id > ACPI_MEM_LIST_MAX) { + return (NULL); + } + + element = acpi_gbl_memory_lists[list_id].list_head; + + /* Search for the address. */ + + while (element) { + if (element == allocation) { + return (element); + } + + element = element->next; + } + + return (NULL); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_track_allocation + * + * PARAMETERS: list_id - Memory list to search + * Allocation - Address of allocated memory + * Size - Size of the allocation + * alloc_type - MEM_MALLOC or MEM_CALLOC + * Component - Component type of caller + * Module - Source file name of caller + * Line - Line number of caller + * + * RETURN: None. + * + * DESCRIPTION: Inserts an element into the global allocation tracking list. + * + ******************************************************************************/ + +acpi_status +acpi_ut_track_allocation ( + u32 list_id, + struct acpi_debug_mem_block *allocation, + acpi_size size, + u8 alloc_type, + u32 component, + char *module, + u32 line) +{ + struct acpi_memory_list *mem_list; + struct acpi_debug_mem_block *element; + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE_PTR ("ut_track_allocation", allocation); + + + if (list_id > ACPI_MEM_LIST_MAX) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + mem_list = &acpi_gbl_memory_lists[list_id]; + status = acpi_ut_acquire_mutex (ACPI_MTX_MEMORY); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* + * Search list for this address to make sure it is not already on the list. + * This will catch several kinds of problems. + */ + + element = acpi_ut_find_allocation (list_id, allocation); + if (element) { + ACPI_REPORT_ERROR (("ut_track_allocation: Allocation already present in list! (%p)\n", + allocation)); + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Element %p Address %p\n", element, allocation)); + + goto unlock_and_exit; + } + + /* Fill in the instance data. */ + + allocation->size = (u32) size; + allocation->alloc_type = alloc_type; + allocation->component = component; + allocation->line = line; + + ACPI_STRNCPY (allocation->module, module, ACPI_MAX_MODULE_NAME); + allocation->module[ACPI_MAX_MODULE_NAME-1] = 0; + + /* Insert at list head */ + + if (mem_list->list_head) { + ((struct acpi_debug_mem_block *)(mem_list->list_head))->previous = allocation; + } + + allocation->next = mem_list->list_head; + allocation->previous = NULL; + + mem_list->list_head = allocation; + + +unlock_and_exit: + status = acpi_ut_release_mutex (ACPI_MTX_MEMORY); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_remove_allocation + * + * PARAMETERS: list_id - Memory list to search + * Allocation - Address of allocated memory + * Component - Component type of caller + * Module - Source file name of caller + * Line - Line number of caller + * + * RETURN: + * + * DESCRIPTION: Deletes an element from the global allocation tracking list. + * + ******************************************************************************/ + +acpi_status +acpi_ut_remove_allocation ( + u32 list_id, + struct acpi_debug_mem_block *allocation, + u32 component, + char *module, + u32 line) +{ + struct acpi_memory_list *mem_list; + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ut_remove_allocation"); + + + if (list_id > ACPI_MEM_LIST_MAX) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + mem_list = &acpi_gbl_memory_lists[list_id]; + if (NULL == mem_list->list_head) { + /* No allocations! */ + + _ACPI_REPORT_ERROR (module, line, component, + ("ut_remove_allocation: Empty allocation list, nothing to free!\n")); + + return_ACPI_STATUS (AE_OK); + } + + status = acpi_ut_acquire_mutex (ACPI_MTX_MEMORY); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Unlink */ + + if (allocation->previous) { + (allocation->previous)->next = allocation->next; + } + else { + mem_list->list_head = allocation->next; + } + + if (allocation->next) { + (allocation->next)->previous = allocation->previous; + } + + /* Mark the segment as deleted */ + + ACPI_MEMSET (&allocation->user_space, 0xEA, allocation->size); + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Freeing size 0%X\n", allocation->size)); + + status = acpi_ut_release_mutex (ACPI_MTX_MEMORY); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_dump_allocation_info + * + * PARAMETERS: + * + * RETURN: None + * + * DESCRIPTION: Print some info about the outstanding allocations. + * + ******************************************************************************/ +#ifdef ACPI_FUTURE_USAGE +void +acpi_ut_dump_allocation_info ( + void) +{ +/* + struct acpi_memory_list *mem_list; +*/ + + ACPI_FUNCTION_TRACE ("ut_dump_allocation_info"); + +/* + ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, + ("%30s: %4d (%3d Kb)\n", "Current allocations", + mem_list->current_count, + ROUND_UP_TO_1K (mem_list->current_size))); + + ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, + ("%30s: %4d (%3d Kb)\n", "Max concurrent allocations", + mem_list->max_concurrent_count, + ROUND_UP_TO_1K (mem_list->max_concurrent_size))); + + + ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, + ("%30s: %4d (%3d Kb)\n", "Total (all) internal objects", + running_object_count, + ROUND_UP_TO_1K (running_object_size))); + + ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, + ("%30s: %4d (%3d Kb)\n", "Total (all) allocations", + running_alloc_count, + ROUND_UP_TO_1K (running_alloc_size))); + + + ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, + ("%30s: %4d (%3d Kb)\n", "Current Nodes", + acpi_gbl_current_node_count, + ROUND_UP_TO_1K (acpi_gbl_current_node_size))); + + ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, + ("%30s: %4d (%3d Kb)\n", "Max Nodes", + acpi_gbl_max_concurrent_node_count, + ROUND_UP_TO_1K ((acpi_gbl_max_concurrent_node_count * sizeof (struct acpi_namespace_node))))); +*/ + return_VOID; +} +#endif /* ACPI_FUTURE_USAGE */ + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_dump_allocations + * + * PARAMETERS: Component - Component(s) to dump info for. + * Module - Module to dump info for. NULL means all. + * + * RETURN: None + * + * DESCRIPTION: Print a list of all outstanding allocations. + * + ******************************************************************************/ + +void +acpi_ut_dump_allocations ( + u32 component, + char *module) +{ + struct acpi_debug_mem_block *element; + union acpi_descriptor *descriptor; + u32 num_outstanding = 0; + + + ACPI_FUNCTION_TRACE ("ut_dump_allocations"); + + + /* + * Walk the allocation list. + */ + if (ACPI_FAILURE (acpi_ut_acquire_mutex (ACPI_MTX_MEMORY))) { + return; + } + + element = acpi_gbl_memory_lists[0].list_head; + while (element) { + if ((element->component & component) && + ((module == NULL) || (0 == ACPI_STRCMP (module, element->module)))) { + /* Ignore allocated objects that are in a cache */ + + descriptor = ACPI_CAST_PTR (union acpi_descriptor, &element->user_space); + if (descriptor->descriptor_id != ACPI_DESC_TYPE_CACHED) { + acpi_os_printf ("%p Len %04X %9.9s-%d [%s] ", + descriptor, element->size, element->module, + element->line, acpi_ut_get_descriptor_name (descriptor)); + + /* Most of the elements will be Operand objects. */ + + switch (ACPI_GET_DESCRIPTOR_TYPE (descriptor)) { + case ACPI_DESC_TYPE_OPERAND: + acpi_os_printf ("%12.12s R%hd", + acpi_ut_get_type_name (descriptor->object.common.type), + descriptor->object.common.reference_count); + break; + + case ACPI_DESC_TYPE_PARSER: + acpi_os_printf ("aml_opcode %04hX", + descriptor->op.asl.aml_opcode); + break; + + case ACPI_DESC_TYPE_NAMED: + acpi_os_printf ("%4.4s", + acpi_ut_get_node_name (&descriptor->node)); + break; + + default: + break; + } + + acpi_os_printf ( "\n"); + num_outstanding++; + } + } + element = element->next; + } + + (void) acpi_ut_release_mutex (ACPI_MTX_MEMORY); + + /* Print summary */ + + if (!num_outstanding) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "No outstanding allocations.\n")); + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "%d(%X) Outstanding allocations\n", + num_outstanding, num_outstanding)); + } + + return_VOID; +} + + +#endif /* #ifdef ACPI_DBG_TRACK_ALLOCATIONS */ + diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c new file mode 100644 index 000000000000..0fcd98bde0d1 --- /dev/null +++ b/drivers/acpi/utilities/utcopy.c @@ -0,0 +1,930 @@ +/****************************************************************************** + * + * Module Name: utcopy - Internal to external object translation utilities + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + + +#include <acpi/acpi.h> +#include <acpi/amlcode.h> + + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utcopy") + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_copy_isimple_to_esimple + * + * PARAMETERS: *internal_object - Pointer to the object we are examining + * *Buffer - Where the object is returned + * *space_used - Where the data length is returned + * + * RETURN: Status + * + * DESCRIPTION: This function is called to place a simple object in a user + * buffer. + * + * The buffer is assumed to have sufficient space for the object. + * + ******************************************************************************/ + +static acpi_status +acpi_ut_copy_isimple_to_esimple ( + union acpi_operand_object *internal_object, + union acpi_object *external_object, + u8 *data_space, + acpi_size *buffer_space_used) +{ + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE ("ut_copy_isimple_to_esimple"); + + + *buffer_space_used = 0; + + /* + * Check for NULL object case (could be an uninitialized + * package element) + */ + if (!internal_object) { + return_ACPI_STATUS (AE_OK); + } + + /* Always clear the external object */ + + ACPI_MEMSET (external_object, 0, sizeof (union acpi_object)); + + /* + * In general, the external object will be the same type as + * the internal object + */ + external_object->type = ACPI_GET_OBJECT_TYPE (internal_object); + + /* However, only a limited number of external types are supported */ + + switch (ACPI_GET_OBJECT_TYPE (internal_object)) { + case ACPI_TYPE_STRING: + + external_object->string.pointer = (char *) data_space; + external_object->string.length = internal_object->string.length; + *buffer_space_used = ACPI_ROUND_UP_TO_NATIVE_WORD ((acpi_size) internal_object->string.length + 1); + + ACPI_MEMCPY ((void *) data_space, (void *) internal_object->string.pointer, + (acpi_size) internal_object->string.length + 1); + break; + + + case ACPI_TYPE_BUFFER: + + external_object->buffer.pointer = data_space; + external_object->buffer.length = internal_object->buffer.length; + *buffer_space_used = ACPI_ROUND_UP_TO_NATIVE_WORD (internal_object->string.length); + + ACPI_MEMCPY ((void *) data_space, (void *) internal_object->buffer.pointer, + internal_object->buffer.length); + break; + + + case ACPI_TYPE_INTEGER: + + external_object->integer.value = internal_object->integer.value; + break; + + + case ACPI_TYPE_LOCAL_REFERENCE: + + /* + * This is an object reference. Attempt to dereference it. + */ + switch (internal_object->reference.opcode) { + case AML_INT_NAMEPATH_OP: + + /* For namepath, return the object handle ("reference") */ + + default: + /* + * Use the object type of "Any" to indicate a reference + * to object containing a handle to an ACPI named object. + */ + external_object->type = ACPI_TYPE_ANY; + external_object->reference.handle = internal_object->reference.node; + break; + } + break; + + + case ACPI_TYPE_PROCESSOR: + + external_object->processor.proc_id = internal_object->processor.proc_id; + external_object->processor.pblk_address = internal_object->processor.address; + external_object->processor.pblk_length = internal_object->processor.length; + break; + + + case ACPI_TYPE_POWER: + + external_object->power_resource.system_level = + internal_object->power_resource.system_level; + + external_object->power_resource.resource_order = + internal_object->power_resource.resource_order; + break; + + + default: + /* + * There is no corresponding external object type + */ + return_ACPI_STATUS (AE_SUPPORT); + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_copy_ielement_to_eelement + * + * PARAMETERS: acpi_pkg_callback + * + * RETURN: Status + * + * DESCRIPTION: Copy one package element to another package element + * + ******************************************************************************/ + +acpi_status +acpi_ut_copy_ielement_to_eelement ( + u8 object_type, + union acpi_operand_object *source_object, + union acpi_generic_state *state, + void *context) +{ + acpi_status status = AE_OK; + struct acpi_pkg_info *info = (struct acpi_pkg_info *) context; + acpi_size object_space; + u32 this_index; + union acpi_object *target_object; + + + ACPI_FUNCTION_ENTRY (); + + + this_index = state->pkg.index; + target_object = (union acpi_object *) + &((union acpi_object *)(state->pkg.dest_object))->package.elements[this_index]; + + switch (object_type) { + case ACPI_COPY_TYPE_SIMPLE: + + /* + * This is a simple or null object + */ + status = acpi_ut_copy_isimple_to_esimple (source_object, + target_object, info->free_space, &object_space); + if (ACPI_FAILURE (status)) { + return (status); + } + break; + + + case ACPI_COPY_TYPE_PACKAGE: + + /* + * Build the package object + */ + target_object->type = ACPI_TYPE_PACKAGE; + target_object->package.count = source_object->package.count; + target_object->package.elements = ACPI_CAST_PTR (union acpi_object, info->free_space); + + /* + * Pass the new package object back to the package walk routine + */ + state->pkg.this_target_obj = target_object; + + /* + * Save space for the array of objects (Package elements) + * update the buffer length counter + */ + object_space = ACPI_ROUND_UP_TO_NATIVE_WORD ( + (acpi_size) target_object->package.count * sizeof (union acpi_object)); + break; + + + default: + return (AE_BAD_PARAMETER); + } + + info->free_space += object_space; + info->length += object_space; + return (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_copy_ipackage_to_epackage + * + * PARAMETERS: *internal_object - Pointer to the object we are returning + * *Buffer - Where the object is returned + * *space_used - Where the object length is returned + * + * RETURN: Status + * + * DESCRIPTION: This function is called to place a package object in a user + * buffer. A package object by definition contains other objects. + * + * The buffer is assumed to have sufficient space for the object. + * The caller must have verified the buffer length needed using the + * acpi_ut_get_object_size function before calling this function. + * + ******************************************************************************/ + +static acpi_status +acpi_ut_copy_ipackage_to_epackage ( + union acpi_operand_object *internal_object, + u8 *buffer, + acpi_size *space_used) +{ + union acpi_object *external_object; + acpi_status status; + struct acpi_pkg_info info; + + + ACPI_FUNCTION_TRACE ("ut_copy_ipackage_to_epackage"); + + + /* + * First package at head of the buffer + */ + external_object = ACPI_CAST_PTR (union acpi_object, buffer); + + /* + * Free space begins right after the first package + */ + info.length = ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (union acpi_object)); + info.free_space = buffer + ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (union acpi_object)); + info.object_space = 0; + info.num_packages = 1; + + external_object->type = ACPI_GET_OBJECT_TYPE (internal_object); + external_object->package.count = internal_object->package.count; + external_object->package.elements = ACPI_CAST_PTR (union acpi_object, info.free_space); + + /* + * Leave room for an array of ACPI_OBJECTS in the buffer + * and move the free space past it + */ + info.length += (acpi_size) external_object->package.count * + ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (union acpi_object)); + info.free_space += external_object->package.count * + ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (union acpi_object)); + + status = acpi_ut_walk_package_tree (internal_object, external_object, + acpi_ut_copy_ielement_to_eelement, &info); + + *space_used = info.length; + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_copy_iobject_to_eobject + * + * PARAMETERS: *internal_object - The internal object to be converted + * *buffer_ptr - Where the object is returned + * + * RETURN: Status + * + * DESCRIPTION: This function is called to build an API object to be returned to + * the caller. + * + ******************************************************************************/ + +acpi_status +acpi_ut_copy_iobject_to_eobject ( + union acpi_operand_object *internal_object, + struct acpi_buffer *ret_buffer) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ut_copy_iobject_to_eobject"); + + + if (ACPI_GET_OBJECT_TYPE (internal_object) == ACPI_TYPE_PACKAGE) { + /* + * Package object: Copy all subobjects (including + * nested packages) + */ + status = acpi_ut_copy_ipackage_to_epackage (internal_object, + ret_buffer->pointer, &ret_buffer->length); + } + else { + /* + * Build a simple object (no nested objects) + */ + status = acpi_ut_copy_isimple_to_esimple (internal_object, + (union acpi_object *) ret_buffer->pointer, + ((u8 *) ret_buffer->pointer + + ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (union acpi_object))), + &ret_buffer->length); + /* + * build simple does not include the object size in the length + * so we add it in here + */ + ret_buffer->length += sizeof (union acpi_object); + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_copy_esimple_to_isimple + * + * PARAMETERS: *external_object - The external object to be converted + * *internal_object - Where the internal object is returned + * + * RETURN: Status + * + * DESCRIPTION: This function copies an external object to an internal one. + * NOTE: Pointers can be copied, we don't need to copy data. + * (The pointers have to be valid in our address space no matter + * what we do with them!) + * + ******************************************************************************/ + +acpi_status +acpi_ut_copy_esimple_to_isimple ( + union acpi_object *external_object, + union acpi_operand_object **ret_internal_object) +{ + union acpi_operand_object *internal_object; + + + ACPI_FUNCTION_TRACE ("ut_copy_esimple_to_isimple"); + + + /* + * Simple types supported are: String, Buffer, Integer + */ + switch (external_object->type) { + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + case ACPI_TYPE_INTEGER: + + internal_object = acpi_ut_create_internal_object ((u8) external_object->type); + if (!internal_object) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + break; + + default: + /* All other types are not supported */ + + return_ACPI_STATUS (AE_SUPPORT); + } + + + /* Must COPY string and buffer contents */ + + switch (external_object->type) { + case ACPI_TYPE_STRING: + + internal_object->string.pointer = + ACPI_MEM_CALLOCATE ((acpi_size) external_object->string.length + 1); + if (!internal_object->string.pointer) { + goto error_exit; + } + + ACPI_MEMCPY (internal_object->string.pointer, + external_object->string.pointer, + external_object->string.length); + + internal_object->string.length = external_object->string.length; + break; + + + case ACPI_TYPE_BUFFER: + + internal_object->buffer.pointer = + ACPI_MEM_CALLOCATE (external_object->buffer.length); + if (!internal_object->buffer.pointer) { + goto error_exit; + } + + ACPI_MEMCPY (internal_object->buffer.pointer, + external_object->buffer.pointer, + external_object->buffer.length); + + internal_object->buffer.length = external_object->buffer.length; + break; + + + case ACPI_TYPE_INTEGER: + + internal_object->integer.value = external_object->integer.value; + break; + + default: + /* Other types can't get here */ + break; + } + + *ret_internal_object = internal_object; + return_ACPI_STATUS (AE_OK); + + +error_exit: + acpi_ut_remove_reference (internal_object); + return_ACPI_STATUS (AE_NO_MEMORY); +} + + +#ifdef ACPI_FUTURE_IMPLEMENTATION + +/* Code to convert packages that are parameters to control methods */ + +/******************************************************************************* + * + * FUNCTION: acpi_ut_copy_epackage_to_ipackage + * + * PARAMETERS: *internal_object - Pointer to the object we are returning + * *Buffer - Where the object is returned + * *space_used - Where the length of the object is returned + * + * RETURN: Status + * + * DESCRIPTION: This function is called to place a package object in a user + * buffer. A package object by definition contains other objects. + * + * The buffer is assumed to have sufficient space for the object. + * The caller must have verified the buffer length needed using the + * acpi_ut_get_object_size function before calling this function. + * + ******************************************************************************/ + +static acpi_status +acpi_ut_copy_epackage_to_ipackage ( + union acpi_operand_object *internal_object, + u8 *buffer, + u32 *space_used) +{ + u8 *free_space; + union acpi_object *external_object; + u32 length = 0; + u32 this_index; + u32 object_space = 0; + union acpi_operand_object *this_internal_obj; + union acpi_object *this_external_obj; + + + ACPI_FUNCTION_TRACE ("ut_copy_epackage_to_ipackage"); + + + /* + * First package at head of the buffer + */ + external_object = (union acpi_object *)buffer; + + /* + * Free space begins right after the first package + */ + free_space = buffer + sizeof(union acpi_object); + + + external_object->type = ACPI_GET_OBJECT_TYPE (internal_object); + external_object->package.count = internal_object->package.count; + external_object->package.elements = (union acpi_object *)free_space; + + /* + * Build an array of ACPI_OBJECTS in the buffer + * and move the free space past it + */ + free_space += external_object->package.count * sizeof(union acpi_object); + + + /* Call walk_package */ + +} + +#endif /* Future implementation */ + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_copy_eobject_to_iobject + * + * PARAMETERS: *internal_object - The external object to be converted + * *buffer_ptr - Where the internal object is returned + * + * RETURN: Status - the status of the call + * + * DESCRIPTION: Converts an external object to an internal object. + * + ******************************************************************************/ + +acpi_status +acpi_ut_copy_eobject_to_iobject ( + union acpi_object *external_object, + union acpi_operand_object **internal_object) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ut_copy_eobject_to_iobject"); + + + if (external_object->type == ACPI_TYPE_PACKAGE) { + /* + * Packages as external input to control methods are not supported, + */ + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Packages as parameters not implemented!\n")); + + return_ACPI_STATUS (AE_NOT_IMPLEMENTED); + } + + else { + /* + * Build a simple object (no nested objects) + */ + status = acpi_ut_copy_esimple_to_isimple (external_object, internal_object); + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_copy_simple_object + * + * PARAMETERS: source_desc - The internal object to be copied + * dest_desc - New target object + * + * RETURN: Status + * + * DESCRIPTION: Simple copy of one internal object to another. Reference count + * of the destination object is preserved. + * + ******************************************************************************/ + +acpi_status +acpi_ut_copy_simple_object ( + union acpi_operand_object *source_desc, + union acpi_operand_object *dest_desc) +{ + u16 reference_count; + union acpi_operand_object *next_object; + + + /* Save fields from destination that we don't want to overwrite */ + + reference_count = dest_desc->common.reference_count; + next_object = dest_desc->common.next_object; + + /* Copy the entire source object over the destination object*/ + + ACPI_MEMCPY ((char *) dest_desc, (char *) source_desc, + sizeof (union acpi_operand_object)); + + /* Restore the saved fields */ + + dest_desc->common.reference_count = reference_count; + dest_desc->common.next_object = next_object; + + /* Handle the objects with extra data */ + + switch (ACPI_GET_OBJECT_TYPE (dest_desc)) { + case ACPI_TYPE_BUFFER: + + dest_desc->buffer.node = NULL; + dest_desc->common.flags = source_desc->common.flags; + + /* + * Allocate and copy the actual buffer if and only if: + * 1) There is a valid buffer pointer + * 2) The buffer is not static (not in an ACPI table) (in this case, + * the actual pointer was already copied above) + */ + if ((source_desc->buffer.pointer) && + (!(source_desc->common.flags & AOPOBJ_STATIC_POINTER))) { + dest_desc->buffer.pointer = NULL; + + /* Create an actual buffer only if length > 0 */ + + if (source_desc->buffer.length) { + dest_desc->buffer.pointer = + ACPI_MEM_ALLOCATE (source_desc->buffer.length); + if (!dest_desc->buffer.pointer) { + return (AE_NO_MEMORY); + } + + /* Copy the actual buffer data */ + + ACPI_MEMCPY (dest_desc->buffer.pointer, + source_desc->buffer.pointer, + source_desc->buffer.length); + } + } + break; + + case ACPI_TYPE_STRING: + + /* + * Allocate and copy the actual string if and only if: + * 1) There is a valid string pointer + * 2) The string is not static (not in an ACPI table) (in this case, + * the actual pointer was already copied above) + */ + if ((source_desc->string.pointer) && + (!(source_desc->common.flags & AOPOBJ_STATIC_POINTER))) { + dest_desc->string.pointer = + ACPI_MEM_ALLOCATE ((acpi_size) source_desc->string.length + 1); + if (!dest_desc->string.pointer) { + return (AE_NO_MEMORY); + } + + ACPI_MEMCPY (dest_desc->string.pointer, source_desc->string.pointer, + (acpi_size) source_desc->string.length + 1); + } + break; + + case ACPI_TYPE_LOCAL_REFERENCE: + /* + * We copied the reference object, so we now must add a reference + * to the object pointed to by the reference + */ + acpi_ut_add_reference (source_desc->reference.object); + break; + + default: + /* Nothing to do for other simple objects */ + break; + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_copy_ielement_to_ielement + * + * PARAMETERS: acpi_pkg_callback + * + * RETURN: Status + * + * DESCRIPTION: Copy one package element to another package element + * + ******************************************************************************/ + +acpi_status +acpi_ut_copy_ielement_to_ielement ( + u8 object_type, + union acpi_operand_object *source_object, + union acpi_generic_state *state, + void *context) +{ + acpi_status status = AE_OK; + u32 this_index; + union acpi_operand_object **this_target_ptr; + union acpi_operand_object *target_object; + + + ACPI_FUNCTION_ENTRY (); + + + this_index = state->pkg.index; + this_target_ptr = (union acpi_operand_object **) + &state->pkg.dest_object->package.elements[this_index]; + + switch (object_type) { + case ACPI_COPY_TYPE_SIMPLE: + + /* A null source object indicates a (legal) null package element */ + + if (source_object) { + /* + * This is a simple object, just copy it + */ + target_object = acpi_ut_create_internal_object ( + ACPI_GET_OBJECT_TYPE (source_object)); + if (!target_object) { + return (AE_NO_MEMORY); + } + + status = acpi_ut_copy_simple_object (source_object, target_object); + if (ACPI_FAILURE (status)) { + goto error_exit; + } + + *this_target_ptr = target_object; + } + else { + /* Pass through a null element */ + + *this_target_ptr = NULL; + } + break; + + + case ACPI_COPY_TYPE_PACKAGE: + + /* + * This object is a package - go down another nesting level + * Create and build the package object + */ + target_object = acpi_ut_create_internal_object (ACPI_TYPE_PACKAGE); + if (!target_object) { + return (AE_NO_MEMORY); + } + + target_object->package.count = source_object->package.count; + target_object->common.flags = source_object->common.flags; + + /* + * Create the object array + */ + target_object->package.elements = + ACPI_MEM_CALLOCATE (((acpi_size) source_object->package.count + 1) * + sizeof (void *)); + if (!target_object->package.elements) { + status = AE_NO_MEMORY; + goto error_exit; + } + + /* + * Pass the new package object back to the package walk routine + */ + state->pkg.this_target_obj = target_object; + + /* + * Store the object pointer in the parent package object + */ + *this_target_ptr = target_object; + break; + + + default: + return (AE_BAD_PARAMETER); + } + + return (status); + +error_exit: + acpi_ut_remove_reference (target_object); + return (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_copy_ipackage_to_ipackage + * + * PARAMETERS: *source_obj - Pointer to the source package object + * *dest_obj - Where the internal object is returned + * + * RETURN: Status - the status of the call + * + * DESCRIPTION: This function is called to copy an internal package object + * into another internal package object. + * + ******************************************************************************/ + +acpi_status +acpi_ut_copy_ipackage_to_ipackage ( + union acpi_operand_object *source_obj, + union acpi_operand_object *dest_obj, + struct acpi_walk_state *walk_state) +{ + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE ("ut_copy_ipackage_to_ipackage"); + + + dest_obj->common.type = ACPI_GET_OBJECT_TYPE (source_obj); + dest_obj->common.flags = source_obj->common.flags; + dest_obj->package.count = source_obj->package.count; + + /* + * Create the object array and walk the source package tree + */ + dest_obj->package.elements = ACPI_MEM_CALLOCATE ( + ((acpi_size) source_obj->package.count + 1) * + sizeof (void *)); + if (!dest_obj->package.elements) { + ACPI_REPORT_ERROR ( + ("aml_build_copy_internal_package_object: Package allocation failure\n")); + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* + * Copy the package element-by-element by walking the package "tree". + * This handles nested packages of arbitrary depth. + */ + status = acpi_ut_walk_package_tree (source_obj, dest_obj, + acpi_ut_copy_ielement_to_ielement, walk_state); + if (ACPI_FAILURE (status)) { + /* On failure, delete the destination package object */ + + acpi_ut_remove_reference (dest_obj); + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_copy_iobject_to_iobject + * + * PARAMETERS: walk_state - Current walk state + * source_desc - The internal object to be copied + * dest_desc - Where the copied object is returned + * + * RETURN: Status + * + * DESCRIPTION: Copy an internal object to a new internal object + * + ******************************************************************************/ + +acpi_status +acpi_ut_copy_iobject_to_iobject ( + union acpi_operand_object *source_desc, + union acpi_operand_object **dest_desc, + struct acpi_walk_state *walk_state) +{ + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE ("ut_copy_iobject_to_iobject"); + + + /* Create the top level object */ + + *dest_desc = acpi_ut_create_internal_object (ACPI_GET_OBJECT_TYPE (source_desc)); + if (!*dest_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Copy the object and possible subobjects */ + + if (ACPI_GET_OBJECT_TYPE (source_desc) == ACPI_TYPE_PACKAGE) { + status = acpi_ut_copy_ipackage_to_ipackage (source_desc, *dest_desc, + walk_state); + } + else { + status = acpi_ut_copy_simple_object (source_desc, *dest_desc); + } + + return_ACPI_STATUS (status); +} + + diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c new file mode 100644 index 000000000000..985c5d045b78 --- /dev/null +++ b/drivers/acpi/utilities/utdebug.c @@ -0,0 +1,624 @@ +/****************************************************************************** + * + * Module Name: utdebug - Debug print routines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include <linux/module.h> + +#include <acpi/acpi.h> + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utdebug") + + +#ifdef ACPI_DEBUG_OUTPUT + +static u32 acpi_gbl_prev_thread_id = 0xFFFFFFFF; +static char *acpi_gbl_fn_entry_str = "----Entry"; +static char *acpi_gbl_fn_exit_str = "----Exit-"; + + +/***************************************************************************** + * + * FUNCTION: acpi_ut_init_stack_ptr_trace + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Save the current stack pointer + * + ****************************************************************************/ + +void +acpi_ut_init_stack_ptr_trace ( + void) +{ + u32 current_sp; + + + acpi_gbl_entry_stack_pointer = ACPI_PTR_DIFF (¤t_sp, NULL); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ut_track_stack_ptr + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Save the current stack pointer + * + ****************************************************************************/ + +void +acpi_ut_track_stack_ptr ( + void) +{ + acpi_size current_sp; + + + current_sp = ACPI_PTR_DIFF (¤t_sp, NULL); + + if (current_sp < acpi_gbl_lowest_stack_pointer) { + acpi_gbl_lowest_stack_pointer = current_sp; + } + + if (acpi_gbl_nesting_level > acpi_gbl_deepest_nesting) { + acpi_gbl_deepest_nesting = acpi_gbl_nesting_level; + } +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ut_debug_print + * + * PARAMETERS: debug_level - Requested debug print level + * proc_name - Caller's procedure name + * module_name - Caller's module name (for error output) + * line_number - Caller's line number (for error output) + * component_id - Caller's component ID (for error output) + * + * Format - Printf format field + * ... - Optional printf arguments + * + * RETURN: None + * + * DESCRIPTION: Print error message with prefix consisting of the module name, + * line number, and component ID. + * + ****************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +acpi_ut_debug_print ( + u32 requested_debug_level, + u32 line_number, + struct acpi_debug_print_info *dbg_info, + char *format, + ...) +{ + u32 thread_id; + va_list args; + + + /* + * Stay silent if the debug level or component ID is disabled + */ + if (!(requested_debug_level & acpi_dbg_level) || + !(dbg_info->component_id & acpi_dbg_layer)) { + return; + } + + /* + * Thread tracking and context switch notification + */ + thread_id = acpi_os_get_thread_id (); + + if (thread_id != acpi_gbl_prev_thread_id) { + if (ACPI_LV_THREADS & acpi_dbg_level) { + acpi_os_printf ("\n**** Context Switch from TID %X to TID %X ****\n\n", + acpi_gbl_prev_thread_id, thread_id); + } + + acpi_gbl_prev_thread_id = thread_id; + } + + /* + * Display the module name, current line number, thread ID (if requested), + * current procedure nesting level, and the current procedure name + */ + acpi_os_printf ("%8s-%04ld ", dbg_info->module_name, line_number); + + if (ACPI_LV_THREADS & acpi_dbg_level) { + acpi_os_printf ("[%04lX] ", thread_id); + } + + acpi_os_printf ("[%02ld] %-22.22s: ", acpi_gbl_nesting_level, dbg_info->proc_name); + + va_start (args, format); + acpi_os_vprintf (format, args); +} +EXPORT_SYMBOL(acpi_ut_debug_print); + + +/***************************************************************************** + * + * FUNCTION: acpi_ut_debug_print_raw + * + * PARAMETERS: requested_debug_level - Requested debug print level + * line_number - Caller's line number + * dbg_info - Contains: + * proc_name - Caller's procedure name + * module_name - Caller's module name + * component_id - Caller's component ID + * Format - Printf format field + * ... - Optional printf arguments + * + * RETURN: None + * + * DESCRIPTION: Print message with no headers. Has same interface as + * debug_print so that the same macros can be used. + * + ****************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +acpi_ut_debug_print_raw ( + u32 requested_debug_level, + u32 line_number, + struct acpi_debug_print_info *dbg_info, + char *format, + ...) +{ + va_list args; + + + if (!(requested_debug_level & acpi_dbg_level) || + !(dbg_info->component_id & acpi_dbg_layer)) { + return; + } + + va_start (args, format); + acpi_os_vprintf (format, args); +} +EXPORT_SYMBOL(acpi_ut_debug_print_raw); + + +/***************************************************************************** + * + * FUNCTION: acpi_ut_trace + * + * PARAMETERS: line_number - Caller's line number + * dbg_info - Contains: + * proc_name - Caller's procedure name + * module_name - Caller's module name + * component_id - Caller's component ID + * + * RETURN: None + * + * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is + * set in debug_level + * + ****************************************************************************/ + +void +acpi_ut_trace ( + u32 line_number, + struct acpi_debug_print_info *dbg_info) +{ + + acpi_gbl_nesting_level++; + acpi_ut_track_stack_ptr (); + + acpi_ut_debug_print (ACPI_LV_FUNCTIONS, line_number, dbg_info, + "%s\n", acpi_gbl_fn_entry_str); +} +EXPORT_SYMBOL(acpi_ut_trace); + + +/***************************************************************************** + * + * FUNCTION: acpi_ut_trace_ptr + * + * PARAMETERS: line_number - Caller's line number + * dbg_info - Contains: + * proc_name - Caller's procedure name + * module_name - Caller's module name + * component_id - Caller's component ID + * Pointer - Pointer to display + * + * RETURN: None + * + * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is + * set in debug_level + * + ****************************************************************************/ + +void +acpi_ut_trace_ptr ( + u32 line_number, + struct acpi_debug_print_info *dbg_info, + void *pointer) +{ + acpi_gbl_nesting_level++; + acpi_ut_track_stack_ptr (); + + acpi_ut_debug_print (ACPI_LV_FUNCTIONS, line_number, dbg_info, + "%s %p\n", acpi_gbl_fn_entry_str, pointer); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ut_trace_str + * + * PARAMETERS: line_number - Caller's line number + * dbg_info - Contains: + * proc_name - Caller's procedure name + * module_name - Caller's module name + * component_id - Caller's component ID + * String - Additional string to display + * + * RETURN: None + * + * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is + * set in debug_level + * + ****************************************************************************/ + +void +acpi_ut_trace_str ( + u32 line_number, + struct acpi_debug_print_info *dbg_info, + char *string) +{ + + acpi_gbl_nesting_level++; + acpi_ut_track_stack_ptr (); + + acpi_ut_debug_print (ACPI_LV_FUNCTIONS, line_number, dbg_info, + "%s %s\n", acpi_gbl_fn_entry_str, string); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ut_trace_u32 + * + * PARAMETERS: line_number - Caller's line number + * dbg_info - Contains: + * proc_name - Caller's procedure name + * module_name - Caller's module name + * component_id - Caller's component ID + * Integer - Integer to display + * + * RETURN: None + * + * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is + * set in debug_level + * + ****************************************************************************/ + +void +acpi_ut_trace_u32 ( + u32 line_number, + struct acpi_debug_print_info *dbg_info, + u32 integer) +{ + + acpi_gbl_nesting_level++; + acpi_ut_track_stack_ptr (); + + acpi_ut_debug_print (ACPI_LV_FUNCTIONS, line_number, dbg_info, + "%s %08X\n", acpi_gbl_fn_entry_str, integer); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ut_exit + * + * PARAMETERS: line_number - Caller's line number + * dbg_info - Contains: + * proc_name - Caller's procedure name + * module_name - Caller's module name + * component_id - Caller's component ID + * + * RETURN: None + * + * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is + * set in debug_level + * + ****************************************************************************/ + +void +acpi_ut_exit ( + u32 line_number, + struct acpi_debug_print_info *dbg_info) +{ + + acpi_ut_debug_print (ACPI_LV_FUNCTIONS, line_number, dbg_info, + "%s\n", acpi_gbl_fn_exit_str); + + acpi_gbl_nesting_level--; +} +EXPORT_SYMBOL(acpi_ut_exit); + + +/***************************************************************************** + * + * FUNCTION: acpi_ut_status_exit + * + * PARAMETERS: line_number - Caller's line number + * dbg_info - Contains: + * proc_name - Caller's procedure name + * module_name - Caller's module name + * component_id - Caller's component ID + * Status - Exit status code + * + * RETURN: None + * + * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is + * set in debug_level. Prints exit status also. + * + ****************************************************************************/ + +void +acpi_ut_status_exit ( + u32 line_number, + struct acpi_debug_print_info *dbg_info, + acpi_status status) +{ + + if (ACPI_SUCCESS (status)) { + acpi_ut_debug_print (ACPI_LV_FUNCTIONS, line_number, dbg_info, + "%s %s\n", acpi_gbl_fn_exit_str, + acpi_format_exception (status)); + } + else { + acpi_ut_debug_print (ACPI_LV_FUNCTIONS, line_number, dbg_info, + "%s ****Exception****: %s\n", acpi_gbl_fn_exit_str, + acpi_format_exception (status)); + } + + acpi_gbl_nesting_level--; +} +EXPORT_SYMBOL(acpi_ut_status_exit); + + +/***************************************************************************** + * + * FUNCTION: acpi_ut_value_exit + * + * PARAMETERS: line_number - Caller's line number + * dbg_info - Contains: + * proc_name - Caller's procedure name + * module_name - Caller's module name + * component_id - Caller's component ID + * Value - Value to be printed with exit msg + * + * RETURN: None + * + * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is + * set in debug_level. Prints exit value also. + * + ****************************************************************************/ + +void +acpi_ut_value_exit ( + u32 line_number, + struct acpi_debug_print_info *dbg_info, + acpi_integer value) +{ + + acpi_ut_debug_print (ACPI_LV_FUNCTIONS, line_number, dbg_info, + "%s %8.8X%8.8X\n", acpi_gbl_fn_exit_str, + ACPI_FORMAT_UINT64 (value)); + + acpi_gbl_nesting_level--; +} +EXPORT_SYMBOL(acpi_ut_value_exit); + + +/***************************************************************************** + * + * FUNCTION: acpi_ut_ptr_exit + * + * PARAMETERS: line_number - Caller's line number + * dbg_info - Contains: + * proc_name - Caller's procedure name + * module_name - Caller's module name + * component_id - Caller's component ID + * Value - Value to be printed with exit msg + * + * RETURN: None + * + * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is + * set in debug_level. Prints exit value also. + * + ****************************************************************************/ + +void +acpi_ut_ptr_exit ( + u32 line_number, + struct acpi_debug_print_info *dbg_info, + u8 *ptr) +{ + + acpi_ut_debug_print (ACPI_LV_FUNCTIONS, line_number, dbg_info, + "%s %p\n", acpi_gbl_fn_exit_str, ptr); + + acpi_gbl_nesting_level--; +} + +#endif + + +/***************************************************************************** + * + * FUNCTION: acpi_ut_dump_buffer + * + * PARAMETERS: Buffer - Buffer to dump + * Count - Amount to dump, in bytes + * Display - BYTE, WORD, DWORD, or QWORD display + * component_iD - Caller's component ID + * + * RETURN: None + * + * DESCRIPTION: Generic dump buffer in both hex and ascii. + * + ****************************************************************************/ + +void +acpi_ut_dump_buffer ( + u8 *buffer, + u32 count, + u32 display, + u32 component_id) +{ + acpi_native_uint i = 0; + acpi_native_uint j; + u32 temp32; + u8 buf_char; + + + /* Only dump the buffer if tracing is enabled */ + + if (!((ACPI_LV_TABLES & acpi_dbg_level) && + (component_id & acpi_dbg_layer))) { + return; + } + + if ((count < 4) || (count & 0x01)) { + display = DB_BYTE_DISPLAY; + } + + acpi_os_printf ("\nOffset Value\n"); + + /* + * Nasty little dump buffer routine! + */ + while (i < count) { + /* Print current offset */ + + acpi_os_printf ("%05X ", (u32) i); + + /* Print 16 hex chars */ + + for (j = 0; j < 16;) { + if (i + j >= count) { + acpi_os_printf ("\n"); + return; + } + + /* Make sure that the s8 doesn't get sign-extended! */ + + switch (display) { + /* Default is BYTE display */ + + default: + + acpi_os_printf ("%02X ", + *((u8 *) &buffer[i + j])); + j += 1; + break; + + + case DB_WORD_DISPLAY: + + ACPI_MOVE_16_TO_32 (&temp32, &buffer[i + j]); + acpi_os_printf ("%04X ", temp32); + j += 2; + break; + + + case DB_DWORD_DISPLAY: + + ACPI_MOVE_32_TO_32 (&temp32, &buffer[i + j]); + acpi_os_printf ("%08X ", temp32); + j += 4; + break; + + + case DB_QWORD_DISPLAY: + + ACPI_MOVE_32_TO_32 (&temp32, &buffer[i + j]); + acpi_os_printf ("%08X", temp32); + + ACPI_MOVE_32_TO_32 (&temp32, &buffer[i + j + 4]); + acpi_os_printf ("%08X ", temp32); + j += 8; + break; + } + } + + /* + * Print the ASCII equivalent characters + * But watch out for the bad unprintable ones... + */ + for (j = 0; j < 16; j++) { + if (i + j >= count) { + acpi_os_printf ("\n"); + return; + } + + buf_char = buffer[i + j]; + if ((buf_char > 0x1F && buf_char < 0x2E) || + (buf_char > 0x2F && buf_char < 0x61) || + (buf_char > 0x60 && buf_char < 0x7F)) { + acpi_os_printf ("%c", buf_char); + } + else { + acpi_os_printf ("."); + } + } + + /* Done with that line. */ + + acpi_os_printf ("\n"); + i += 16; + } + + return; +} + diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c new file mode 100644 index 000000000000..9a52ad52a23a --- /dev/null +++ b/drivers/acpi/utilities/utdelete.c @@ -0,0 +1,700 @@ +/******************************************************************************* + * + * Module Name: utdelete - object deletion and reference count utilities + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + + +#include <acpi/acpi.h> +#include <acpi/acinterp.h> +#include <acpi/acnamesp.h> +#include <acpi/acevents.h> +#include <acpi/amlcode.h> + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utdelete") + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_delete_internal_obj + * + * PARAMETERS: *Object - Pointer to the list to be deleted + * + * RETURN: None + * + * DESCRIPTION: Low level object deletion, after reference counts have been + * updated (All reference counts, including sub-objects!) + * + ******************************************************************************/ + +void +acpi_ut_delete_internal_obj ( + union acpi_operand_object *object) +{ + void *obj_pointer = NULL; + union acpi_operand_object *handler_desc; + union acpi_operand_object *second_desc; + union acpi_operand_object *next_desc; + + + ACPI_FUNCTION_TRACE_PTR ("ut_delete_internal_obj", object); + + + if (!object) { + return_VOID; + } + + /* + * Must delete or free any pointers within the object that are not + * actual ACPI objects (for example, a raw buffer pointer). + */ + switch (ACPI_GET_OBJECT_TYPE (object)) { + case ACPI_TYPE_STRING: + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "**** String %p, ptr %p\n", + object, object->string.pointer)); + + /* Free the actual string buffer */ + + if (!(object->common.flags & AOPOBJ_STATIC_POINTER)) { + /* But only if it is NOT a pointer into an ACPI table */ + + obj_pointer = object->string.pointer; + } + break; + + + case ACPI_TYPE_BUFFER: + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "**** Buffer %p, ptr %p\n", + object, object->buffer.pointer)); + + /* Free the actual buffer */ + + if (!(object->common.flags & AOPOBJ_STATIC_POINTER)) { + /* But only if it is NOT a pointer into an ACPI table */ + + obj_pointer = object->buffer.pointer; + } + break; + + + case ACPI_TYPE_PACKAGE: + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, " **** Package of count %X\n", + object->package.count)); + + /* + * Elements of the package are not handled here, they are deleted + * separately + */ + + /* Free the (variable length) element pointer array */ + + obj_pointer = object->package.elements; + break; + + + case ACPI_TYPE_DEVICE: + + if (object->device.gpe_block) { + (void) acpi_ev_delete_gpe_block (object->device.gpe_block); + } + + /* Walk the handler list for this device */ + + handler_desc = object->device.handler; + while (handler_desc) { + next_desc = handler_desc->address_space.next; + acpi_ut_remove_reference (handler_desc); + handler_desc = next_desc; + } + break; + + + case ACPI_TYPE_MUTEX: + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Mutex %p, Semaphore %p\n", + object, object->mutex.semaphore)); + + acpi_ex_unlink_mutex (object); + (void) acpi_os_delete_semaphore (object->mutex.semaphore); + break; + + + case ACPI_TYPE_EVENT: + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Event %p, Semaphore %p\n", + object, object->event.semaphore)); + + (void) acpi_os_delete_semaphore (object->event.semaphore); + object->event.semaphore = NULL; + break; + + + case ACPI_TYPE_METHOD: + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Method %p\n", object)); + + /* Delete the method semaphore if it exists */ + + if (object->method.semaphore) { + (void) acpi_os_delete_semaphore (object->method.semaphore); + object->method.semaphore = NULL; + } + break; + + + case ACPI_TYPE_REGION: + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Region %p\n", object)); + + second_desc = acpi_ns_get_secondary_object (object); + if (second_desc) { + /* + * Free the region_context if and only if the handler is one of the + * default handlers -- and therefore, we created the context object + * locally, it was not created by an external caller. + */ + handler_desc = object->region.handler; + if (handler_desc) { + if (handler_desc->address_space.hflags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) { + obj_pointer = second_desc->extra.region_context; + } + + acpi_ut_remove_reference (handler_desc); + } + + /* Now we can free the Extra object */ + + acpi_ut_delete_object_desc (second_desc); + } + break; + + + case ACPI_TYPE_BUFFER_FIELD: + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Buffer Field %p\n", object)); + + second_desc = acpi_ns_get_secondary_object (object); + if (second_desc) { + acpi_ut_delete_object_desc (second_desc); + } + break; + + + default: + break; + } + + /* Free any allocated memory (pointer within the object) found above */ + + if (obj_pointer) { + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Deleting Object Subptr %p\n", + obj_pointer)); + ACPI_MEM_FREE (obj_pointer); + } + + /* Now the object can be safely deleted */ + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Deleting Object %p [%s]\n", + object, acpi_ut_get_object_type_name (object))); + + acpi_ut_delete_object_desc (object); + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_delete_internal_object_list + * + * PARAMETERS: *obj_list - Pointer to the list to be deleted + * + * RETURN: None + * + * DESCRIPTION: This function deletes an internal object list, including both + * simple objects and package objects + * + ******************************************************************************/ + +void +acpi_ut_delete_internal_object_list ( + union acpi_operand_object **obj_list) +{ + union acpi_operand_object **internal_obj; + + + ACPI_FUNCTION_TRACE ("ut_delete_internal_object_list"); + + + /* Walk the null-terminated internal list */ + + for (internal_obj = obj_list; *internal_obj; internal_obj++) { + acpi_ut_remove_reference (*internal_obj); + } + + /* Free the combined parameter pointer list and object array */ + + ACPI_MEM_FREE (obj_list); + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_update_ref_count + * + * PARAMETERS: *Object - Object whose ref count is to be updated + * Action - What to do + * + * RETURN: New ref count + * + * DESCRIPTION: Modify the ref count and return it. + * + ******************************************************************************/ + +static void +acpi_ut_update_ref_count ( + union acpi_operand_object *object, + u32 action) +{ + u16 count; + u16 new_count; + + + ACPI_FUNCTION_NAME ("ut_update_ref_count"); + + + if (!object) { + return; + } + + count = object->common.reference_count; + new_count = count; + + /* + * Perform the reference count action (increment, decrement, or force delete) + */ + switch (action) { + + case REF_INCREMENT: + + new_count++; + object->common.reference_count = new_count; + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, [Incremented]\n", + object, new_count)); + break; + + + case REF_DECREMENT: + + if (count < 1) { + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, can't decrement! (Set to 0)\n", + object, new_count)); + + new_count = 0; + } + else { + new_count--; + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, [Decremented]\n", + object, new_count)); + } + + if (ACPI_GET_OBJECT_TYPE (object) == ACPI_TYPE_METHOD) { + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Method Obj %p Refs=%X, [Decremented]\n", + object, new_count)); + } + + object->common.reference_count = new_count; + if (new_count == 0) { + acpi_ut_delete_internal_obj (object); + } + + break; + + + case REF_FORCE_DELETE: + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, Force delete! (Set to 0)\n", + object, count)); + + new_count = 0; + object->common.reference_count = new_count; + acpi_ut_delete_internal_obj (object); + break; + + + default: + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown action (%X)\n", action)); + break; + } + + /* + * Sanity check the reference count, for debug purposes only. + * (A deleted object will have a huge reference count) + */ + if (count > ACPI_MAX_REFERENCE_COUNT) { + + ACPI_DEBUG_PRINT ((ACPI_DB_WARN, + "**** Warning **** Large Reference Count (%X) in object %p\n\n", + count, object)); + } + + return; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_update_object_reference + * + * PARAMETERS: *Object - Increment ref count for this object + * and all sub-objects + * Action - Either REF_INCREMENT or REF_DECREMENT or + * REF_FORCE_DELETE + * + * RETURN: Status + * + * DESCRIPTION: Increment the object reference count + * + * Object references are incremented when: + * 1) An object is attached to a Node (namespace object) + * 2) An object is copied (all subobjects must be incremented) + * + * Object references are decremented when: + * 1) An object is detached from an Node + * + ******************************************************************************/ + +acpi_status +acpi_ut_update_object_reference ( + union acpi_operand_object *object, + u16 action) +{ + acpi_status status; + u32 i; + union acpi_generic_state *state_list = NULL; + union acpi_generic_state *state; + union acpi_operand_object *tmp; + + ACPI_FUNCTION_TRACE_PTR ("ut_update_object_reference", object); + + + /* Ignore a null object ptr */ + + if (!object) { + return_ACPI_STATUS (AE_OK); + } + + /* Make sure that this isn't a namespace handle */ + + if (ACPI_GET_DESCRIPTOR_TYPE (object) == ACPI_DESC_TYPE_NAMED) { + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Object %p is NS handle\n", object)); + return_ACPI_STATUS (AE_OK); + } + + state = acpi_ut_create_update_state (object, action); + + while (state) { + object = state->update.object; + action = state->update.value; + acpi_ut_delete_generic_state (state); + + /* + * All sub-objects must have their reference count incremented also. + * Different object types have different subobjects. + */ + switch (ACPI_GET_OBJECT_TYPE (object)) { + case ACPI_TYPE_DEVICE: + + tmp = object->device.system_notify; + if (tmp && (tmp->common.reference_count <= 1) && action == REF_DECREMENT) + object->device.system_notify = NULL; + acpi_ut_update_ref_count (tmp, action); + + tmp = object->device.device_notify; + if (tmp && (tmp->common.reference_count <= 1) && action == REF_DECREMENT) + object->device.device_notify = NULL; + acpi_ut_update_ref_count (tmp, action); + + break; + + + case ACPI_TYPE_PACKAGE: + + /* + * We must update all the sub-objects of the package + * (Each of whom may have their own sub-objects, etc. + */ + for (i = 0; i < object->package.count; i++) { + /* + * Push each element onto the stack for later processing. + * Note: There can be null elements within the package, + * these are simply ignored + */ + status = acpi_ut_create_update_state_and_push ( + object->package.elements[i], action, &state_list); + if (ACPI_FAILURE (status)) { + goto error_exit; + } + + tmp = object->package.elements[i]; + if (tmp && (tmp->common.reference_count <= 1) && action == REF_DECREMENT) + object->package.elements[i] = NULL; + } + break; + + + case ACPI_TYPE_BUFFER_FIELD: + + status = acpi_ut_create_update_state_and_push ( + object->buffer_field.buffer_obj, action, &state_list); + if (ACPI_FAILURE (status)) { + goto error_exit; + } + + tmp = object->buffer_field.buffer_obj; + if ( tmp && (tmp->common.reference_count <= 1) && action == REF_DECREMENT) + object->buffer_field.buffer_obj = NULL; + break; + + + case ACPI_TYPE_LOCAL_REGION_FIELD: + + status = acpi_ut_create_update_state_and_push ( + object->field.region_obj, action, &state_list); + if (ACPI_FAILURE (status)) { + goto error_exit; + } + + tmp = object->field.region_obj; + if ( tmp && (tmp->common.reference_count <= 1) && action == REF_DECREMENT) + object->field.region_obj = NULL; + break; + + + case ACPI_TYPE_LOCAL_BANK_FIELD: + + status = acpi_ut_create_update_state_and_push ( + object->bank_field.bank_obj, action, &state_list); + if (ACPI_FAILURE (status)) { + goto error_exit; + } + + tmp = object->bank_field.bank_obj; + if ( tmp && (tmp->common.reference_count <= 1) && action == REF_DECREMENT) + object->bank_field.bank_obj = NULL; + + status = acpi_ut_create_update_state_and_push ( + object->bank_field.region_obj, action, &state_list); + if (ACPI_FAILURE (status)) { + goto error_exit; + } + + tmp = object->bank_field.region_obj; + if ( tmp && (tmp->common.reference_count <= 1) && action == REF_DECREMENT) + object->bank_field.region_obj = NULL; + break; + + + case ACPI_TYPE_LOCAL_INDEX_FIELD: + + status = acpi_ut_create_update_state_and_push ( + object->index_field.index_obj, action, &state_list); + if (ACPI_FAILURE (status)) { + goto error_exit; + } + + tmp = object->index_field.index_obj; + if ( tmp && (tmp->common.reference_count <= 1) && action == REF_DECREMENT) + object->index_field.index_obj = NULL; + + status = acpi_ut_create_update_state_and_push ( + object->index_field.data_obj, action, &state_list); + if (ACPI_FAILURE (status)) { + goto error_exit; + } + + tmp = object->index_field.data_obj; + if ( tmp && (tmp->common.reference_count <= 1) && action == REF_DECREMENT) + object->index_field.data_obj = NULL; + break; + + + case ACPI_TYPE_LOCAL_REFERENCE: + + /* + * The target of an Index (a package, string, or buffer) must track + * changes to the ref count of the index. + */ + if (object->reference.opcode == AML_INDEX_OP) { + status = acpi_ut_create_update_state_and_push ( + object->reference.object, action, &state_list); + if (ACPI_FAILURE (status)) { + goto error_exit; + } + } + break; + + + case ACPI_TYPE_REGION: + default: + + /* No subobjects */ + break; + } + + /* + * Now we can update the count in the main object. This can only + * happen after we update the sub-objects in case this causes the + * main object to be deleted. + */ + acpi_ut_update_ref_count (object, action); + + /* Move on to the next object to be updated */ + + state = acpi_ut_pop_generic_state (&state_list); + } + + return_ACPI_STATUS (AE_OK); + + +error_exit: + + ACPI_REPORT_ERROR (("Could not update object reference count, %s\n", + acpi_format_exception (status))); + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_add_reference + * + * PARAMETERS: *Object - Object whose reference count is to be + * incremented + * + * RETURN: None + * + * DESCRIPTION: Add one reference to an ACPI object + * + ******************************************************************************/ + +void +acpi_ut_add_reference ( + union acpi_operand_object *object) +{ + + ACPI_FUNCTION_TRACE_PTR ("ut_add_reference", object); + + + /* Ensure that we have a valid object */ + + if (!acpi_ut_valid_internal_object (object)) { + return_VOID; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "Obj %p Current Refs=%X [To Be Incremented]\n", + object, object->common.reference_count)); + + /* Increment the reference count */ + + (void) acpi_ut_update_object_reference (object, REF_INCREMENT); + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_remove_reference + * + * PARAMETERS: *Object - Object whose ref count will be decremented + * + * RETURN: None + * + * DESCRIPTION: Decrement the reference count of an ACPI internal object + * + ******************************************************************************/ + +void +acpi_ut_remove_reference ( + union acpi_operand_object *object) +{ + + ACPI_FUNCTION_TRACE_PTR ("ut_remove_reference", object); + + + /* + * Allow a NULL pointer to be passed in, just ignore it. This saves + * each caller from having to check. Also, ignore NS nodes. + * + */ + if (!object || + (ACPI_GET_DESCRIPTOR_TYPE (object) == ACPI_DESC_TYPE_NAMED)) { + return_VOID; + } + + /* Ensure that we have a valid object */ + + if (!acpi_ut_valid_internal_object (object)) { + return_VOID; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "Obj %p Current Refs=%X [To Be Decremented]\n", + object, object->common.reference_count)); + + /* + * Decrement the reference count, and only actually delete the object + * if the reference count becomes 0. (Must also decrement the ref count + * of all subobjects!) + */ + (void) acpi_ut_update_object_reference (object, REF_DECREMENT); + return_VOID; +} + + diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c new file mode 100644 index 000000000000..ead27d2c4d18 --- /dev/null +++ b/drivers/acpi/utilities/uteval.c @@ -0,0 +1,696 @@ +/****************************************************************************** + * + * Module Name: uteval - Object evaluation + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + + +#include <acpi/acpi.h> +#include <acpi/acnamesp.h> +#include <acpi/acinterp.h> + + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("uteval") + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_osi_implementation + * + * PARAMETERS: walk_state - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Implementation of _OSI predefined control method + * Supported = _OSI (String) + * + ******************************************************************************/ + +acpi_status +acpi_ut_osi_implementation ( + struct acpi_walk_state *walk_state) +{ + union acpi_operand_object *string_desc; + union acpi_operand_object *return_desc; + acpi_native_uint i; + + + ACPI_FUNCTION_TRACE ("ut_osi_implementation"); + + + /* Validate the string input argument */ + + string_desc = walk_state->arguments[0].object; + if (!string_desc || (string_desc->common.type != ACPI_TYPE_STRING)) { + return_ACPI_STATUS (AE_TYPE); + } + + /* Create a return object (Default value = 0) */ + + return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); + if (!return_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Compare input string to table of supported strings */ + + for (i = 0; i < ACPI_NUM_OSI_STRINGS; i++) { + if (!ACPI_STRCMP (string_desc->string.pointer, + (char *) acpi_gbl_valid_osi_strings[i])) { + /* This string is supported */ + + return_desc->integer.value = 0xFFFFFFFF; + break; + } + } + + walk_state->return_desc = return_desc; + return_ACPI_STATUS (AE_CTRL_TERMINATE); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_evaluate_object + * + * PARAMETERS: prefix_node - Starting node + * Path - Path to object from starting node + * expected_return_types - Bitmap of allowed return types + * return_desc - Where a return value is stored + * + * RETURN: Status + * + * DESCRIPTION: Evaluates a namespace object and verifies the type of the + * return object. Common code that simplifies accessing objects + * that have required return objects of fixed types. + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +acpi_status +acpi_ut_evaluate_object ( + struct acpi_namespace_node *prefix_node, + char *path, + u32 expected_return_btypes, + union acpi_operand_object **return_desc) +{ + struct acpi_parameter_info info; + acpi_status status; + u32 return_btype; + + + ACPI_FUNCTION_TRACE ("ut_evaluate_object"); + + + info.node = prefix_node; + info.parameters = NULL; + info.parameter_type = ACPI_PARAM_ARGS; + + /* Evaluate the object/method */ + + status = acpi_ns_evaluate_relative (path, &info); + if (ACPI_FAILURE (status)) { + if (status == AE_NOT_FOUND) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s.%s] was not found\n", + acpi_ut_get_node_name (prefix_node), path)); + } + else { + ACPI_REPORT_METHOD_ERROR ("Method execution failed", + prefix_node, path, status); + } + + return_ACPI_STATUS (status); + } + + /* Did we get a return object? */ + + if (!info.return_object) { + if (expected_return_btypes) { + ACPI_REPORT_METHOD_ERROR ("No object was returned from", + prefix_node, path, AE_NOT_EXIST); + + return_ACPI_STATUS (AE_NOT_EXIST); + } + + return_ACPI_STATUS (AE_OK); + } + + /* Map the return object type to the bitmapped type */ + + switch (ACPI_GET_OBJECT_TYPE (info.return_object)) { + case ACPI_TYPE_INTEGER: + return_btype = ACPI_BTYPE_INTEGER; + break; + + case ACPI_TYPE_BUFFER: + return_btype = ACPI_BTYPE_BUFFER; + break; + + case ACPI_TYPE_STRING: + return_btype = ACPI_BTYPE_STRING; + break; + + case ACPI_TYPE_PACKAGE: + return_btype = ACPI_BTYPE_PACKAGE; + break; + + default: + return_btype = 0; + break; + } + + if ((acpi_gbl_enable_interpreter_slack) && + (!expected_return_btypes)) { + /* + * We received a return object, but one was not expected. This can + * happen frequently if the "implicit return" feature is enabled. + * Just delete the return object and return AE_OK. + */ + acpi_ut_remove_reference (info.return_object); + return_ACPI_STATUS (AE_OK); + } + + /* Is the return object one of the expected types? */ + + if (!(expected_return_btypes & return_btype)) { + ACPI_REPORT_METHOD_ERROR ("Return object type is incorrect", + prefix_node, path, AE_TYPE); + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Type returned from %s was incorrect: %s, expected Btypes: %X\n", + path, acpi_ut_get_object_type_name (info.return_object), + expected_return_btypes)); + + /* On error exit, we must delete the return object */ + + acpi_ut_remove_reference (info.return_object); + return_ACPI_STATUS (AE_TYPE); + } + + /* Object type is OK, return it */ + + *return_desc = info.return_object; + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_evaluate_numeric_object + * + * PARAMETERS: *object_name - Object name to be evaluated + * device_node - Node for the device + * *Address - Where the value is returned + * + * RETURN: Status + * + * DESCRIPTION: Evaluates a numeric namespace object for a selected device + * and stores result in *Address. + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +acpi_status +acpi_ut_evaluate_numeric_object ( + char *object_name, + struct acpi_namespace_node *device_node, + acpi_integer *address) +{ + union acpi_operand_object *obj_desc; + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ut_evaluate_numeric_object"); + + + status = acpi_ut_evaluate_object (device_node, object_name, + ACPI_BTYPE_INTEGER, &obj_desc); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Get the returned Integer */ + + *address = obj_desc->integer.value; + + /* On exit, we must delete the return object */ + + acpi_ut_remove_reference (obj_desc); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_copy_id_string + * + * PARAMETERS: Destination - Where to copy the string + * Source - Source string + * max_length - Length of the destination buffer + * + * RETURN: None + * + * DESCRIPTION: Copies an ID string for the _HID, _CID, and _UID methods. + * Performs removal of a leading asterisk if present -- workaround + * for a known issue on a bunch of machines. + * + ******************************************************************************/ + +static void +acpi_ut_copy_id_string ( + char *destination, + char *source, + acpi_size max_length) +{ + + + /* + * Workaround for ID strings that have a leading asterisk. This construct + * is not allowed by the ACPI specification (ID strings must be + * alphanumeric), but enough existing machines have this embedded in their + * ID strings that the following code is useful. + */ + if (*source == '*') { + source++; + } + + /* Do the actual copy */ + + ACPI_STRNCPY (destination, source, max_length); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_execute_HID + * + * PARAMETERS: device_node - Node for the device + * *Hid - Where the HID is returned + * + * RETURN: Status + * + * DESCRIPTION: Executes the _HID control method that returns the hardware + * ID of the device. + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +acpi_status +acpi_ut_execute_HID ( + struct acpi_namespace_node *device_node, + struct acpi_device_id *hid) +{ + union acpi_operand_object *obj_desc; + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ut_execute_HID"); + + + status = acpi_ut_evaluate_object (device_node, METHOD_NAME__HID, + ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING, &obj_desc); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) { + /* Convert the Numeric HID to string */ + + acpi_ex_eisa_id_to_string ((u32) obj_desc->integer.value, hid->value); + } + else { + /* Copy the String HID from the returned object */ + + acpi_ut_copy_id_string (hid->value, obj_desc->string.pointer, + sizeof (hid->value)); + } + + /* On exit, we must delete the return object */ + + acpi_ut_remove_reference (obj_desc); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_translate_one_cid + * + * PARAMETERS: obj_desc - _CID object, must be integer or string + * one_cid - Where the CID string is returned + * + * RETURN: Status + * + * DESCRIPTION: Return a numeric or string _CID value as a string. + * (Compatible ID) + * + * NOTE: Assumes a maximum _CID string length of + * ACPI_MAX_CID_LENGTH. + * + ******************************************************************************/ + +static acpi_status +acpi_ut_translate_one_cid ( + union acpi_operand_object *obj_desc, + struct acpi_compatible_id *one_cid) +{ + + + switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { + case ACPI_TYPE_INTEGER: + + /* Convert the Numeric CID to string */ + + acpi_ex_eisa_id_to_string ((u32) obj_desc->integer.value, one_cid->value); + return (AE_OK); + + case ACPI_TYPE_STRING: + + if (obj_desc->string.length > ACPI_MAX_CID_LENGTH) { + return (AE_AML_STRING_LIMIT); + } + + /* Copy the String CID from the returned object */ + + acpi_ut_copy_id_string (one_cid->value, obj_desc->string.pointer, + ACPI_MAX_CID_LENGTH); + return (AE_OK); + + default: + + return (AE_TYPE); + } +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_execute_CID + * + * PARAMETERS: device_node - Node for the device + * *Cid - Where the CID is returned + * + * RETURN: Status + * + * DESCRIPTION: Executes the _CID control method that returns one or more + * compatible hardware IDs for the device. + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +acpi_status +acpi_ut_execute_CID ( + struct acpi_namespace_node *device_node, + struct acpi_compatible_id_list **return_cid_list) +{ + union acpi_operand_object *obj_desc; + acpi_status status; + u32 count; + u32 size; + struct acpi_compatible_id_list *cid_list; + acpi_native_uint i; + + + ACPI_FUNCTION_TRACE ("ut_execute_CID"); + + + /* Evaluate the _CID method for this device */ + + status = acpi_ut_evaluate_object (device_node, METHOD_NAME__CID, + ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING | ACPI_BTYPE_PACKAGE, + &obj_desc); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Get the number of _CIDs returned */ + + count = 1; + if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_PACKAGE) { + count = obj_desc->package.count; + } + + /* Allocate a worst-case buffer for the _CIDs */ + + size = (((count - 1) * sizeof (struct acpi_compatible_id)) + + sizeof (struct acpi_compatible_id_list)); + + cid_list = ACPI_MEM_CALLOCATE ((acpi_size) size); + if (!cid_list) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Init CID list */ + + cid_list->count = count; + cid_list->size = size; + + /* + * A _CID can return either a single compatible ID or a package of compatible + * IDs. Each compatible ID can be one of the following: + * -- Number (32 bit compressed EISA ID) or + * -- String (PCI ID format, e.g. "PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss"). + */ + + /* The _CID object can be either a single CID or a package (list) of CIDs */ + + if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_PACKAGE) { + /* Translate each package element */ + + for (i = 0; i < count; i++) { + status = acpi_ut_translate_one_cid (obj_desc->package.elements[i], + &cid_list->id[i]); + if (ACPI_FAILURE (status)) { + break; + } + } + } + else { + /* Only one CID, translate to a string */ + + status = acpi_ut_translate_one_cid (obj_desc, cid_list->id); + } + + /* Cleanup on error */ + + if (ACPI_FAILURE (status)) { + ACPI_MEM_FREE (cid_list); + } + else { + *return_cid_list = cid_list; + } + + /* On exit, we must delete the _CID return object */ + + acpi_ut_remove_reference (obj_desc); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_execute_UID + * + * PARAMETERS: device_node - Node for the device + * *Uid - Where the UID is returned + * + * RETURN: Status + * + * DESCRIPTION: Executes the _UID control method that returns the hardware + * ID of the device. + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +acpi_status +acpi_ut_execute_UID ( + struct acpi_namespace_node *device_node, + struct acpi_device_id *uid) +{ + union acpi_operand_object *obj_desc; + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ut_execute_UID"); + + + status = acpi_ut_evaluate_object (device_node, METHOD_NAME__UID, + ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING, &obj_desc); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) { + /* Convert the Numeric UID to string */ + + acpi_ex_unsigned_integer_to_string (obj_desc->integer.value, uid->value); + } + else { + /* Copy the String UID from the returned object */ + + acpi_ut_copy_id_string (uid->value, obj_desc->string.pointer, + sizeof (uid->value)); + } + + /* On exit, we must delete the return object */ + + acpi_ut_remove_reference (obj_desc); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_execute_STA + * + * PARAMETERS: device_node - Node for the device + * *Flags - Where the status flags are returned + * + * RETURN: Status + * + * DESCRIPTION: Executes _STA for selected device and stores results in + * *Flags. + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +acpi_status +acpi_ut_execute_STA ( + struct acpi_namespace_node *device_node, + u32 *flags) +{ + union acpi_operand_object *obj_desc; + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ut_execute_STA"); + + + status = acpi_ut_evaluate_object (device_node, METHOD_NAME__STA, + ACPI_BTYPE_INTEGER, &obj_desc); + if (ACPI_FAILURE (status)) { + if (AE_NOT_FOUND == status) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "_STA on %4.4s was not found, assuming device is present\n", + acpi_ut_get_node_name (device_node))); + + *flags = 0x0F; + status = AE_OK; + } + + return_ACPI_STATUS (status); + } + + /* Extract the status flags */ + + *flags = (u32) obj_desc->integer.value; + + /* On exit, we must delete the return object */ + + acpi_ut_remove_reference (obj_desc); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_execute_Sxds + * + * PARAMETERS: device_node - Node for the device + * *Flags - Where the status flags are returned + * + * RETURN: Status + * + * DESCRIPTION: Executes _STA for selected device and stores results in + * *Flags. + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +acpi_status +acpi_ut_execute_sxds ( + struct acpi_namespace_node *device_node, + u8 *highest) +{ + union acpi_operand_object *obj_desc; + acpi_status status; + u32 i; + + + ACPI_FUNCTION_TRACE ("ut_execute_Sxds"); + + + for (i = 0; i < 4; i++) { + highest[i] = 0xFF; + status = acpi_ut_evaluate_object (device_node, + (char *) acpi_gbl_highest_dstate_names[i], + ACPI_BTYPE_INTEGER, &obj_desc); + if (ACPI_FAILURE (status)) { + if (status != AE_NOT_FOUND) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "%s on Device %4.4s, %s\n", + (char *) acpi_gbl_highest_dstate_names[i], + acpi_ut_get_node_name (device_node), + acpi_format_exception (status))); + + return_ACPI_STATUS (status); + } + } + else { + /* Extract the Dstate value */ + + highest[i] = (u8) obj_desc->integer.value; + + /* Delete the return object */ + + acpi_ut_remove_reference (obj_desc); + } + } + + return_ACPI_STATUS (AE_OK); +} diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c new file mode 100644 index 000000000000..25b0f8ae1bc6 --- /dev/null +++ b/drivers/acpi/utilities/utglobal.c @@ -0,0 +1,935 @@ +/****************************************************************************** + * + * Module Name: utglobal - Global variables for the ACPI subsystem + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define DEFINE_ACPI_GLOBALS + +#include <linux/module.h> + +#include <acpi/acpi.h> +#include <acpi/acnamesp.h> + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utglobal") + + +/****************************************************************************** + * + * FUNCTION: acpi_format_exception + * + * PARAMETERS: Status - The acpi_status code to be formatted + * + * RETURN: A string containing the exception text + * + * DESCRIPTION: This function translates an ACPI exception into an ASCII string. + * + ******************************************************************************/ + +const char * +acpi_format_exception ( + acpi_status status) +{ + const char *exception = "UNKNOWN_STATUS_CODE"; + acpi_status sub_status; + + + ACPI_FUNCTION_NAME ("format_exception"); + + + sub_status = (status & ~AE_CODE_MASK); + + switch (status & AE_CODE_MASK) { + case AE_CODE_ENVIRONMENTAL: + + if (sub_status <= AE_CODE_ENV_MAX) { + exception = acpi_gbl_exception_names_env [sub_status]; + break; + } + goto unknown; + + case AE_CODE_PROGRAMMER: + + if (sub_status <= AE_CODE_PGM_MAX) { + exception = acpi_gbl_exception_names_pgm [sub_status -1]; + break; + } + goto unknown; + + case AE_CODE_ACPI_TABLES: + + if (sub_status <= AE_CODE_TBL_MAX) { + exception = acpi_gbl_exception_names_tbl [sub_status -1]; + break; + } + goto unknown; + + case AE_CODE_AML: + + if (sub_status <= AE_CODE_AML_MAX) { + exception = acpi_gbl_exception_names_aml [sub_status -1]; + break; + } + goto unknown; + + case AE_CODE_CONTROL: + + if (sub_status <= AE_CODE_CTRL_MAX) { + exception = acpi_gbl_exception_names_ctrl [sub_status -1]; + break; + } + goto unknown; + + default: + goto unknown; + } + + + return ((const char *) exception); + +unknown: + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown exception code: 0x%8.8X\n", status)); + return ((const char *) exception); +} + + +/****************************************************************************** + * + * Static global variable initialization. + * + ******************************************************************************/ + +/* + * We want the debug switches statically initialized so they + * are already set when the debugger is entered. + */ + +/* Debug switch - level and trace mask */ +u32 acpi_dbg_level = ACPI_DEBUG_DEFAULT; +EXPORT_SYMBOL(acpi_dbg_level); + +/* Debug switch - layer (component) mask */ + +u32 acpi_dbg_layer = ACPI_COMPONENT_DEFAULT | ACPI_ALL_DRIVERS; +EXPORT_SYMBOL(acpi_dbg_layer); +u32 acpi_gbl_nesting_level = 0; + + +/* Debugger globals */ + +u8 acpi_gbl_db_terminate_threads = FALSE; +u8 acpi_gbl_abort_method = FALSE; +u8 acpi_gbl_method_executing = FALSE; + +/* System flags */ + +u32 acpi_gbl_startup_flags = 0; + +/* System starts uninitialized */ + +u8 acpi_gbl_shutdown = TRUE; + +const u8 acpi_gbl_decode_to8bit [8] = {1,2,4,8,16,32,64,128}; + +const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = +{ + "\\_S0_", + "\\_S1_", + "\\_S2_", + "\\_S3_", + "\\_S4_", + "\\_S5_" +}; + +const char *acpi_gbl_highest_dstate_names[4] = +{ + "_S1D", + "_S2D", + "_S3D", + "_S4D" +}; + +/* + * Strings supported by the _OSI predefined (internal) method. + * When adding strings, be sure to update ACPI_NUM_OSI_STRINGS. + */ +const char *acpi_gbl_valid_osi_strings[ACPI_NUM_OSI_STRINGS] = +{ + /* Operating System Vendor Strings */ + + "Linux", + "Windows 2000", + "Windows 2001", + "Windows 2001.1", + "Windows 2001 SP0", + "Windows 2001 SP1", + "Windows 2001 SP2", + "Windows 2001 SP3", + "Windows 2001 SP4", + + /* Feature Group Strings */ + + "Extended Address Space Descriptor" +}; + + +/****************************************************************************** + * + * Namespace globals + * + ******************************************************************************/ + + +/* + * Predefined ACPI Names (Built-in to the Interpreter) + * + * NOTES: + * 1) _SB_ is defined to be a device to allow \_SB_._INI to be run + * during the initialization sequence. + * 2) _TZ_ is defined to be a thermal zone in order to allow ASL code to + * perform a Notify() operation on it. + */ +const struct acpi_predefined_names acpi_gbl_pre_defined_names[] = +{ {"_GPE", ACPI_TYPE_LOCAL_SCOPE, NULL}, + {"_PR_", ACPI_TYPE_LOCAL_SCOPE, NULL}, + {"_SB_", ACPI_TYPE_DEVICE, NULL}, + {"_SI_", ACPI_TYPE_LOCAL_SCOPE, NULL}, + {"_TZ_", ACPI_TYPE_THERMAL, NULL}, + {"_REV", ACPI_TYPE_INTEGER, (char *) ACPI_CA_SUPPORT_LEVEL}, + {"_OS_", ACPI_TYPE_STRING, ACPI_OS_NAME}, + {"_GL_", ACPI_TYPE_MUTEX, (char *) 1}, + +#if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY) + {"_OSI", ACPI_TYPE_METHOD, (char *) 1}, +#endif + {NULL, ACPI_TYPE_ANY, NULL} /* Table terminator */ +}; + + +/* + * Properties of the ACPI Object Types, both internal and external. + * The table is indexed by values of acpi_object_type + */ +const u8 acpi_gbl_ns_properties[] = +{ + ACPI_NS_NORMAL, /* 00 Any */ + ACPI_NS_NORMAL, /* 01 Number */ + ACPI_NS_NORMAL, /* 02 String */ + ACPI_NS_NORMAL, /* 03 Buffer */ + ACPI_NS_NORMAL, /* 04 Package */ + ACPI_NS_NORMAL, /* 05 field_unit */ + ACPI_NS_NEWSCOPE, /* 06 Device */ + ACPI_NS_NORMAL, /* 07 Event */ + ACPI_NS_NEWSCOPE, /* 08 Method */ + ACPI_NS_NORMAL, /* 09 Mutex */ + ACPI_NS_NORMAL, /* 10 Region */ + ACPI_NS_NEWSCOPE, /* 11 Power */ + ACPI_NS_NEWSCOPE, /* 12 Processor */ + ACPI_NS_NEWSCOPE, /* 13 Thermal */ + ACPI_NS_NORMAL, /* 14 buffer_field */ + ACPI_NS_NORMAL, /* 15 ddb_handle */ + ACPI_NS_NORMAL, /* 16 Debug Object */ + ACPI_NS_NORMAL, /* 17 def_field */ + ACPI_NS_NORMAL, /* 18 bank_field */ + ACPI_NS_NORMAL, /* 19 index_field */ + ACPI_NS_NORMAL, /* 20 Reference */ + ACPI_NS_NORMAL, /* 21 Alias */ + ACPI_NS_NORMAL, /* 22 method_alias */ + ACPI_NS_NORMAL, /* 23 Notify */ + ACPI_NS_NORMAL, /* 24 Address Handler */ + ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL, /* 25 Resource Desc */ + ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL, /* 26 Resource Field */ + ACPI_NS_NEWSCOPE, /* 27 Scope */ + ACPI_NS_NORMAL, /* 28 Extra */ + ACPI_NS_NORMAL, /* 29 Data */ + ACPI_NS_NORMAL /* 30 Invalid */ +}; + + +/* Hex to ASCII conversion table */ + +static const char acpi_gbl_hex_to_ascii[] = + {'0','1','2','3','4','5','6','7', + '8','9','A','B','C','D','E','F'}; + +/***************************************************************************** + * + * FUNCTION: acpi_ut_hex_to_ascii_char + * + * PARAMETERS: Integer - Contains the hex digit + * Position - bit position of the digit within the + * integer + * + * RETURN: Ascii character + * + * DESCRIPTION: Convert a hex digit to an ascii character + * + ****************************************************************************/ + +char +acpi_ut_hex_to_ascii_char ( + acpi_integer integer, + u32 position) +{ + + return (acpi_gbl_hex_to_ascii[(integer >> position) & 0xF]); +} + + +/****************************************************************************** + * + * Table name globals + * + * NOTE: This table includes ONLY the ACPI tables that the subsystem consumes. + * it is NOT an exhaustive list of all possible ACPI tables. All ACPI tables + * that are not used by the subsystem are simply ignored. + * + * Do NOT add any table to this list that is not consumed directly by this + * subsystem. + * + ******************************************************************************/ + +struct acpi_table_list acpi_gbl_table_lists[NUM_ACPI_TABLE_TYPES]; + +struct acpi_table_support acpi_gbl_table_data[NUM_ACPI_TABLE_TYPES] = +{ + /*********** Name, Signature, Global typed pointer Signature size, Type How many allowed?, Contains valid AML? */ + + /* RSDP 0 */ {RSDP_NAME, RSDP_SIG, NULL, sizeof (RSDP_SIG)-1, ACPI_TABLE_ROOT | ACPI_TABLE_SINGLE}, + /* DSDT 1 */ {DSDT_SIG, DSDT_SIG, (void *) &acpi_gbl_DSDT, sizeof (DSDT_SIG)-1, ACPI_TABLE_SECONDARY| ACPI_TABLE_SINGLE | ACPI_TABLE_EXECUTABLE}, + /* FADT 2 */ {FADT_SIG, FADT_SIG, (void *) &acpi_gbl_FADT, sizeof (FADT_SIG)-1, ACPI_TABLE_PRIMARY | ACPI_TABLE_SINGLE}, + /* FACS 3 */ {FACS_SIG, FACS_SIG, (void *) &acpi_gbl_FACS, sizeof (FACS_SIG)-1, ACPI_TABLE_SECONDARY| ACPI_TABLE_SINGLE}, + /* PSDT 4 */ {PSDT_SIG, PSDT_SIG, NULL, sizeof (PSDT_SIG)-1, ACPI_TABLE_PRIMARY | ACPI_TABLE_MULTIPLE | ACPI_TABLE_EXECUTABLE}, + /* SSDT 5 */ {SSDT_SIG, SSDT_SIG, NULL, sizeof (SSDT_SIG)-1, ACPI_TABLE_PRIMARY | ACPI_TABLE_MULTIPLE | ACPI_TABLE_EXECUTABLE}, + /* XSDT 6 */ {XSDT_SIG, XSDT_SIG, NULL, sizeof (RSDT_SIG)-1, ACPI_TABLE_ROOT | ACPI_TABLE_SINGLE}, +}; + + +/****************************************************************************** + * + * Event and Hardware globals + * + ******************************************************************************/ + +struct acpi_bit_register_info acpi_gbl_bit_register_info[ACPI_NUM_BITREG] = +{ + /* Name Parent Register Register Bit Position Register Bit Mask */ + + /* ACPI_BITREG_TIMER_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_TIMER_STATUS, ACPI_BITMASK_TIMER_STATUS}, + /* ACPI_BITREG_BUS_MASTER_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_BUS_MASTER_STATUS, ACPI_BITMASK_BUS_MASTER_STATUS}, + /* ACPI_BITREG_GLOBAL_LOCK_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_GLOBAL_LOCK_STATUS, ACPI_BITMASK_GLOBAL_LOCK_STATUS}, + /* ACPI_BITREG_POWER_BUTTON_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_POWER_BUTTON_STATUS, ACPI_BITMASK_POWER_BUTTON_STATUS}, + /* ACPI_BITREG_SLEEP_BUTTON_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_SLEEP_BUTTON_STATUS, ACPI_BITMASK_SLEEP_BUTTON_STATUS}, + /* ACPI_BITREG_RT_CLOCK_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_RT_CLOCK_STATUS, ACPI_BITMASK_RT_CLOCK_STATUS}, + /* ACPI_BITREG_WAKE_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_WAKE_STATUS, ACPI_BITMASK_WAKE_STATUS}, + /* ACPI_BITREG_PCIEXP_WAKE_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_PCIEXP_WAKE_STATUS, ACPI_BITMASK_PCIEXP_WAKE_STATUS}, + + /* ACPI_BITREG_TIMER_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, ACPI_BITPOSITION_TIMER_ENABLE, ACPI_BITMASK_TIMER_ENABLE}, + /* ACPI_BITREG_GLOBAL_LOCK_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, ACPI_BITPOSITION_GLOBAL_LOCK_ENABLE, ACPI_BITMASK_GLOBAL_LOCK_ENABLE}, + /* ACPI_BITREG_POWER_BUTTON_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, ACPI_BITPOSITION_POWER_BUTTON_ENABLE, ACPI_BITMASK_POWER_BUTTON_ENABLE}, + /* ACPI_BITREG_SLEEP_BUTTON_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, ACPI_BITPOSITION_SLEEP_BUTTON_ENABLE, ACPI_BITMASK_SLEEP_BUTTON_ENABLE}, + /* ACPI_BITREG_RT_CLOCK_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, ACPI_BITPOSITION_RT_CLOCK_ENABLE, ACPI_BITMASK_RT_CLOCK_ENABLE}, + /* ACPI_BITREG_WAKE_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, 0, 0}, + /* ACPI_BITREG_PCIEXP_WAKE_DISABLE */ {ACPI_REGISTER_PM1_ENABLE, ACPI_BITPOSITION_PCIEXP_WAKE_DISABLE, ACPI_BITMASK_PCIEXP_WAKE_DISABLE}, + + /* ACPI_BITREG_SCI_ENABLE */ {ACPI_REGISTER_PM1_CONTROL, ACPI_BITPOSITION_SCI_ENABLE, ACPI_BITMASK_SCI_ENABLE}, + /* ACPI_BITREG_BUS_MASTER_RLD */ {ACPI_REGISTER_PM1_CONTROL, ACPI_BITPOSITION_BUS_MASTER_RLD, ACPI_BITMASK_BUS_MASTER_RLD}, + /* ACPI_BITREG_GLOBAL_LOCK_RELEASE */ {ACPI_REGISTER_PM1_CONTROL, ACPI_BITPOSITION_GLOBAL_LOCK_RELEASE, ACPI_BITMASK_GLOBAL_LOCK_RELEASE}, + /* ACPI_BITREG_SLEEP_TYPE_A */ {ACPI_REGISTER_PM1_CONTROL, ACPI_BITPOSITION_SLEEP_TYPE_X, ACPI_BITMASK_SLEEP_TYPE_X}, + /* ACPI_BITREG_SLEEP_TYPE_B */ {ACPI_REGISTER_PM1_CONTROL, ACPI_BITPOSITION_SLEEP_TYPE_X, ACPI_BITMASK_SLEEP_TYPE_X}, + /* ACPI_BITREG_SLEEP_ENABLE */ {ACPI_REGISTER_PM1_CONTROL, ACPI_BITPOSITION_SLEEP_ENABLE, ACPI_BITMASK_SLEEP_ENABLE}, + + /* ACPI_BITREG_ARB_DIS */ {ACPI_REGISTER_PM2_CONTROL, ACPI_BITPOSITION_ARB_DISABLE, ACPI_BITMASK_ARB_DISABLE} +}; + + +struct acpi_fixed_event_info acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVENTS] = +{ + /* ACPI_EVENT_PMTIMER */ {ACPI_BITREG_TIMER_STATUS, ACPI_BITREG_TIMER_ENABLE, ACPI_BITMASK_TIMER_STATUS, ACPI_BITMASK_TIMER_ENABLE}, + /* ACPI_EVENT_GLOBAL */ {ACPI_BITREG_GLOBAL_LOCK_STATUS, ACPI_BITREG_GLOBAL_LOCK_ENABLE, ACPI_BITMASK_GLOBAL_LOCK_STATUS, ACPI_BITMASK_GLOBAL_LOCK_ENABLE}, + /* ACPI_EVENT_POWER_BUTTON */ {ACPI_BITREG_POWER_BUTTON_STATUS, ACPI_BITREG_POWER_BUTTON_ENABLE, ACPI_BITMASK_POWER_BUTTON_STATUS, ACPI_BITMASK_POWER_BUTTON_ENABLE}, + /* ACPI_EVENT_SLEEP_BUTTON */ {ACPI_BITREG_SLEEP_BUTTON_STATUS, ACPI_BITREG_SLEEP_BUTTON_ENABLE, ACPI_BITMASK_SLEEP_BUTTON_STATUS, ACPI_BITMASK_SLEEP_BUTTON_ENABLE}, + /* ACPI_EVENT_RTC */ {ACPI_BITREG_RT_CLOCK_STATUS, ACPI_BITREG_RT_CLOCK_ENABLE, ACPI_BITMASK_RT_CLOCK_STATUS, ACPI_BITMASK_RT_CLOCK_ENABLE}, +}; + +/***************************************************************************** + * + * FUNCTION: acpi_ut_get_region_name + * + * PARAMETERS: None. + * + * RETURN: Status + * + * DESCRIPTION: Translate a Space ID into a name string (Debug only) + * + ****************************************************************************/ + +/* Region type decoding */ + +const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS] = +{ +/*! [Begin] no source code translation (keep these ASL Keywords as-is) */ + "SystemMemory", + "SystemIO", + "PCI_Config", + "EmbeddedControl", + "SMBus", + "CMOS", + "PCIBARTarget", + "DataTable" +/*! [End] no source code translation !*/ +}; + + +char * +acpi_ut_get_region_name ( + u8 space_id) +{ + + if (space_id >= ACPI_USER_REGION_BEGIN) + { + return ("user_defined_region"); + } + + else if (space_id >= ACPI_NUM_PREDEFINED_REGIONS) + { + return ("invalid_space_id"); + } + + return ((char *) acpi_gbl_region_types[space_id]); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ut_get_event_name + * + * PARAMETERS: None. + * + * RETURN: Status + * + * DESCRIPTION: Translate a Event ID into a name string (Debug only) + * + ****************************************************************************/ + +/* Event type decoding */ + +static const char *acpi_gbl_event_types[ACPI_NUM_FIXED_EVENTS] = +{ + "PM_Timer", + "global_lock", + "power_button", + "sleep_button", + "real_time_clock", +}; + + +char * +acpi_ut_get_event_name ( + u32 event_id) +{ + + if (event_id > ACPI_EVENT_MAX) + { + return ("invalid_event_iD"); + } + + return ((char *) acpi_gbl_event_types[event_id]); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ut_get_type_name + * + * PARAMETERS: None. + * + * RETURN: Status + * + * DESCRIPTION: Translate a Type ID into a name string (Debug only) + * + ****************************************************************************/ + +/* + * Elements of acpi_gbl_ns_type_names below must match + * one-to-one with values of acpi_object_type + * + * The type ACPI_TYPE_ANY (Untyped) is used as a "don't care" when searching; when + * stored in a table it really means that we have thus far seen no evidence to + * indicate what type is actually going to be stored for this entry. + */ +static const char acpi_gbl_bad_type[] = "UNDEFINED"; +#define TYPE_NAME_LENGTH 12 /* Maximum length of each string */ + +static const char *acpi_gbl_ns_type_names[] = /* printable names of ACPI types */ +{ + /* 00 */ "Untyped", + /* 01 */ "Integer", + /* 02 */ "String", + /* 03 */ "Buffer", + /* 04 */ "Package", + /* 05 */ "field_unit", + /* 06 */ "Device", + /* 07 */ "Event", + /* 08 */ "Method", + /* 09 */ "Mutex", + /* 10 */ "Region", + /* 11 */ "Power", + /* 12 */ "Processor", + /* 13 */ "Thermal", + /* 14 */ "buffer_field", + /* 15 */ "ddb_handle", + /* 16 */ "debug_object", + /* 17 */ "region_field", + /* 18 */ "bank_field", + /* 19 */ "index_field", + /* 20 */ "Reference", + /* 21 */ "Alias", + /* 22 */ "method_alias", + /* 23 */ "Notify", + /* 24 */ "addr_handler", + /* 25 */ "resource_desc", + /* 26 */ "resource_fld", + /* 27 */ "Scope", + /* 28 */ "Extra", + /* 29 */ "Data", + /* 30 */ "Invalid" +}; + + +char * +acpi_ut_get_type_name ( + acpi_object_type type) +{ + + if (type > ACPI_TYPE_INVALID) + { + return ((char *) acpi_gbl_bad_type); + } + + return ((char *) acpi_gbl_ns_type_names[type]); +} + + +char * +acpi_ut_get_object_type_name ( + union acpi_operand_object *obj_desc) +{ + + if (!obj_desc) + { + return ("[NULL Object Descriptor]"); + } + + return (acpi_ut_get_type_name (ACPI_GET_OBJECT_TYPE (obj_desc))); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ut_get_node_name + * + * PARAMETERS: Object - A namespace node + * + * RETURN: Pointer to a string + * + * DESCRIPTION: Validate the node and return the node's ACPI name. + * + ****************************************************************************/ + +char * +acpi_ut_get_node_name ( + void *object) +{ + struct acpi_namespace_node *node = (struct acpi_namespace_node *) object; + + + /* Must return a string of exactly 4 characters == ACPI_NAME_SIZE */ + + if (!object) + { + return ("NULL"); + } + + /* Check for Root node */ + + if ((object == ACPI_ROOT_OBJECT) || + (object == acpi_gbl_root_node)) + { + return ("\"\\\" "); + } + + /* Descriptor must be a namespace node */ + + if (node->descriptor != ACPI_DESC_TYPE_NAMED) + { + return ("####"); + } + + /* Name must be a valid ACPI name */ + + if (!acpi_ut_valid_acpi_name (* (u32 *) node->name.ascii)) + { + return ("????"); + } + + /* Return the name */ + + return (node->name.ascii); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ut_get_descriptor_name + * + * PARAMETERS: Object - An ACPI object + * + * RETURN: Pointer to a string + * + * DESCRIPTION: Validate object and return the descriptor type + * + ****************************************************************************/ + +static const char *acpi_gbl_desc_type_names[] = /* printable names of descriptor types */ +{ + /* 00 */ "Invalid", + /* 01 */ "Cached", + /* 02 */ "State-Generic", + /* 03 */ "State-Update", + /* 04 */ "State-Package", + /* 05 */ "State-Control", + /* 06 */ "State-root_parse_scope", + /* 07 */ "State-parse_scope", + /* 08 */ "State-walk_scope", + /* 09 */ "State-Result", + /* 10 */ "State-Notify", + /* 11 */ "State-Thread", + /* 12 */ "Walk", + /* 13 */ "Parser", + /* 14 */ "Operand", + /* 15 */ "Node" +}; + + +char * +acpi_ut_get_descriptor_name ( + void *object) +{ + + if (!object) + { + return ("NULL OBJECT"); + } + + if (ACPI_GET_DESCRIPTOR_TYPE (object) > ACPI_DESC_TYPE_MAX) + { + return ((char *) acpi_gbl_bad_type); + } + + return ((char *) acpi_gbl_desc_type_names[ACPI_GET_DESCRIPTOR_TYPE (object)]); + +} + + +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) +/* + * Strings and procedures used for debug only + */ + +/***************************************************************************** + * + * FUNCTION: acpi_ut_get_mutex_name + * + * PARAMETERS: None. + * + * RETURN: Status + * + * DESCRIPTION: Translate a mutex ID into a name string (Debug only) + * + ****************************************************************************/ + +char * +acpi_ut_get_mutex_name ( + u32 mutex_id) +{ + + if (mutex_id > MAX_MUTEX) + { + return ("Invalid Mutex ID"); + } + + return (acpi_gbl_mutex_names[mutex_id]); +} + +#endif + + +/***************************************************************************** + * + * FUNCTION: acpi_ut_valid_object_type + * + * PARAMETERS: Type - Object type to be validated + * + * RETURN: TRUE if valid object type + * + * DESCRIPTION: Validate an object type + * + ****************************************************************************/ + +u8 +acpi_ut_valid_object_type ( + acpi_object_type type) +{ + + if (type > ACPI_TYPE_LOCAL_MAX) + { + /* Note: Assumes all TYPEs are contiguous (external/local) */ + + return (FALSE); + } + + return (TRUE); +} + + +/**************************************************************************** + * + * FUNCTION: acpi_ut_allocate_owner_id + * + * PARAMETERS: id_type - Type of ID (method or table) + * + * DESCRIPTION: Allocate a table or method owner id + * + ***************************************************************************/ + +acpi_owner_id +acpi_ut_allocate_owner_id ( + u32 id_type) +{ + acpi_owner_id owner_id = 0xFFFF; + + + ACPI_FUNCTION_TRACE ("ut_allocate_owner_id"); + + + if (ACPI_FAILURE (acpi_ut_acquire_mutex (ACPI_MTX_CACHES))) + { + return (0); + } + + switch (id_type) + { + case ACPI_OWNER_TYPE_TABLE: + + owner_id = acpi_gbl_next_table_owner_id; + acpi_gbl_next_table_owner_id++; + + /* Check for wraparound */ + + if (acpi_gbl_next_table_owner_id == ACPI_FIRST_METHOD_ID) + { + acpi_gbl_next_table_owner_id = ACPI_FIRST_TABLE_ID; + ACPI_REPORT_WARNING (("Table owner ID wraparound\n")); + } + break; + + + case ACPI_OWNER_TYPE_METHOD: + + owner_id = acpi_gbl_next_method_owner_id; + acpi_gbl_next_method_owner_id++; + + if (acpi_gbl_next_method_owner_id == ACPI_FIRST_TABLE_ID) + { + /* Check for wraparound */ + + acpi_gbl_next_method_owner_id = ACPI_FIRST_METHOD_ID; + } + break; + + default: + break; + } + + (void) acpi_ut_release_mutex (ACPI_MTX_CACHES); + return_VALUE (owner_id); +} + + +/**************************************************************************** + * + * FUNCTION: acpi_ut_init_globals + * + * PARAMETERS: none + * + * DESCRIPTION: Init library globals. All globals that require specific + * initialization should be initialized here! + * + ***************************************************************************/ + +void +acpi_ut_init_globals ( + void) +{ + u32 i; + + + ACPI_FUNCTION_TRACE ("ut_init_globals"); + + + /* Memory allocation and cache lists */ + + ACPI_MEMSET (acpi_gbl_memory_lists, 0, sizeof (struct acpi_memory_list) * ACPI_NUM_MEM_LISTS); + + acpi_gbl_memory_lists[ACPI_MEM_LIST_STATE].link_offset = (u16) ACPI_PTR_DIFF (&(((union acpi_generic_state *) NULL)->common.next), NULL); + acpi_gbl_memory_lists[ACPI_MEM_LIST_PSNODE].link_offset = (u16) ACPI_PTR_DIFF (&(((union acpi_parse_object *) NULL)->common.next), NULL); + acpi_gbl_memory_lists[ACPI_MEM_LIST_PSNODE_EXT].link_offset = (u16) ACPI_PTR_DIFF (&(((union acpi_parse_object *) NULL)->common.next), NULL); + acpi_gbl_memory_lists[ACPI_MEM_LIST_OPERAND].link_offset = (u16) ACPI_PTR_DIFF (&(((union acpi_operand_object *) NULL)->cache.next), NULL); + acpi_gbl_memory_lists[ACPI_MEM_LIST_WALK].link_offset = (u16) ACPI_PTR_DIFF (&(((struct acpi_walk_state *) NULL)->next), NULL); + + acpi_gbl_memory_lists[ACPI_MEM_LIST_NSNODE].object_size = sizeof (struct acpi_namespace_node); + acpi_gbl_memory_lists[ACPI_MEM_LIST_STATE].object_size = sizeof (union acpi_generic_state); + acpi_gbl_memory_lists[ACPI_MEM_LIST_PSNODE].object_size = sizeof (struct acpi_parse_obj_common); + acpi_gbl_memory_lists[ACPI_MEM_LIST_PSNODE_EXT].object_size = sizeof (struct acpi_parse_obj_named); + acpi_gbl_memory_lists[ACPI_MEM_LIST_OPERAND].object_size = sizeof (union acpi_operand_object); + acpi_gbl_memory_lists[ACPI_MEM_LIST_WALK].object_size = sizeof (struct acpi_walk_state); + + acpi_gbl_memory_lists[ACPI_MEM_LIST_STATE].max_cache_depth = ACPI_MAX_STATE_CACHE_DEPTH; + acpi_gbl_memory_lists[ACPI_MEM_LIST_PSNODE].max_cache_depth = ACPI_MAX_PARSE_CACHE_DEPTH; + acpi_gbl_memory_lists[ACPI_MEM_LIST_PSNODE_EXT].max_cache_depth = ACPI_MAX_EXTPARSE_CACHE_DEPTH; + acpi_gbl_memory_lists[ACPI_MEM_LIST_OPERAND].max_cache_depth = ACPI_MAX_OBJECT_CACHE_DEPTH; + acpi_gbl_memory_lists[ACPI_MEM_LIST_WALK].max_cache_depth = ACPI_MAX_WALK_CACHE_DEPTH; + + ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].list_name = "Global Memory Allocation"); + ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_NSNODE].list_name = "Namespace Nodes"); + ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_STATE].list_name = "State Object Cache"); + ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_PSNODE].list_name = "Parse Node Cache"); + ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_PSNODE_EXT].list_name = "Extended Parse Node Cache"); + ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_OPERAND].list_name = "Operand Object Cache"); + ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_WALK].list_name = "Tree Walk Node Cache"); + + /* ACPI table structure */ + + for (i = 0; i < NUM_ACPI_TABLE_TYPES; i++) + { + acpi_gbl_table_lists[i].next = NULL; + acpi_gbl_table_lists[i].count = 0; + } + + /* Mutex locked flags */ + + for (i = 0; i < NUM_MUTEX; i++) + { + acpi_gbl_mutex_info[i].mutex = NULL; + acpi_gbl_mutex_info[i].owner_id = ACPI_MUTEX_NOT_ACQUIRED; + acpi_gbl_mutex_info[i].use_count = 0; + } + + /* GPE support */ + + acpi_gbl_gpe_xrupt_list_head = NULL; + acpi_gbl_gpe_fadt_blocks[0] = NULL; + acpi_gbl_gpe_fadt_blocks[1] = NULL; + + /* Global notify handlers */ + + acpi_gbl_system_notify.handler = NULL; + acpi_gbl_device_notify.handler = NULL; + acpi_gbl_exception_handler = NULL; + acpi_gbl_init_handler = NULL; + + /* Global "typed" ACPI table pointers */ + + acpi_gbl_RSDP = NULL; + acpi_gbl_XSDT = NULL; + acpi_gbl_FACS = NULL; + acpi_gbl_FADT = NULL; + acpi_gbl_DSDT = NULL; + + /* Global Lock support */ + + acpi_gbl_global_lock_acquired = FALSE; + acpi_gbl_global_lock_thread_count = 0; + acpi_gbl_global_lock_handle = 0; + + /* Miscellaneous variables */ + + acpi_gbl_table_flags = ACPI_PHYSICAL_POINTER; + acpi_gbl_rsdp_original_location = 0; + acpi_gbl_cm_single_step = FALSE; + acpi_gbl_db_terminate_threads = FALSE; + acpi_gbl_shutdown = FALSE; + acpi_gbl_ns_lookup_count = 0; + acpi_gbl_ps_find_count = 0; + acpi_gbl_acpi_hardware_present = TRUE; + acpi_gbl_next_table_owner_id = ACPI_FIRST_TABLE_ID; + acpi_gbl_next_method_owner_id = ACPI_FIRST_METHOD_ID; + acpi_gbl_debugger_configuration = DEBUGGER_THREADING; + acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT; + + /* Hardware oriented */ + + acpi_gbl_events_initialized = FALSE; + acpi_gbl_system_awake_and_running = TRUE; + + /* Namespace */ + + acpi_gbl_root_node = NULL; + + acpi_gbl_root_node_struct.name.integer = ACPI_ROOT_NAME; + acpi_gbl_root_node_struct.descriptor = ACPI_DESC_TYPE_NAMED; + acpi_gbl_root_node_struct.type = ACPI_TYPE_DEVICE; + acpi_gbl_root_node_struct.child = NULL; + acpi_gbl_root_node_struct.peer = NULL; + acpi_gbl_root_node_struct.object = NULL; + acpi_gbl_root_node_struct.flags = ANOBJ_END_OF_PEER_LIST; + + +#ifdef ACPI_DEBUG_OUTPUT + acpi_gbl_lowest_stack_pointer = ACPI_SIZE_MAX; +#endif + + return_VOID; +} + + diff --git a/drivers/acpi/utilities/utinit.c b/drivers/acpi/utilities/utinit.c new file mode 100644 index 000000000000..bdbadaf48d29 --- /dev/null +++ b/drivers/acpi/utilities/utinit.c @@ -0,0 +1,266 @@ +/****************************************************************************** + * + * Module Name: utinit - Common ACPI subsystem initialization + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + + +#include <acpi/acpi.h> +#include <acpi/acnamesp.h> +#include <acpi/acevents.h> + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utinit") + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_fadt_register_error + * + * PARAMETERS: *register_name - Pointer to string identifying register + * Value - Actual register contents value + * acpi_test_spec_section - TDS section containing assertion + * acpi_assertion - Assertion number being tested + * + * RETURN: AE_BAD_VALUE + * + * DESCRIPTION: Display failure message and link failure to TDS assertion + * + ******************************************************************************/ + +static void +acpi_ut_fadt_register_error ( + char *register_name, + u32 value, + acpi_size offset) +{ + + ACPI_REPORT_WARNING ( + ("Invalid FADT value %s=%X at offset %X FADT=%p\n", + register_name, value, (u32) offset, acpi_gbl_FADT)); +} + + +/****************************************************************************** + * + * FUNCTION: acpi_ut_validate_fadt + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Validate various ACPI registers in the FADT + * + ******************************************************************************/ + +acpi_status +acpi_ut_validate_fadt ( + void) +{ + + /* + * Verify Fixed ACPI Description Table fields, + * but don't abort on any problems, just display error + */ + if (acpi_gbl_FADT->pm1_evt_len < 4) { + acpi_ut_fadt_register_error ("PM1_EVT_LEN", + (u32) acpi_gbl_FADT->pm1_evt_len, + ACPI_FADT_OFFSET (pm1_evt_len)); + } + + if (!acpi_gbl_FADT->pm1_cnt_len) { + acpi_ut_fadt_register_error ("PM1_CNT_LEN", 0, + ACPI_FADT_OFFSET (pm1_cnt_len)); + } + + if (!acpi_gbl_FADT->xpm1a_evt_blk.address) { + acpi_ut_fadt_register_error ("X_PM1a_EVT_BLK", 0, + ACPI_FADT_OFFSET (xpm1a_evt_blk.address)); + } + + if (!acpi_gbl_FADT->xpm1a_cnt_blk.address) { + acpi_ut_fadt_register_error ("X_PM1a_CNT_BLK", 0, + ACPI_FADT_OFFSET (xpm1a_cnt_blk.address)); + } + + if (!acpi_gbl_FADT->xpm_tmr_blk.address) { + acpi_ut_fadt_register_error ("X_PM_TMR_BLK", 0, + ACPI_FADT_OFFSET (xpm_tmr_blk.address)); + } + + if ((acpi_gbl_FADT->xpm2_cnt_blk.address && + !acpi_gbl_FADT->pm2_cnt_len)) { + acpi_ut_fadt_register_error ("PM2_CNT_LEN", + (u32) acpi_gbl_FADT->pm2_cnt_len, + ACPI_FADT_OFFSET (pm2_cnt_len)); + } + + if (acpi_gbl_FADT->pm_tm_len < 4) { + acpi_ut_fadt_register_error ("PM_TM_LEN", + (u32) acpi_gbl_FADT->pm_tm_len, + ACPI_FADT_OFFSET (pm_tm_len)); + } + + /* Length of GPE blocks must be a multiple of 2 */ + + if (acpi_gbl_FADT->xgpe0_blk.address && + (acpi_gbl_FADT->gpe0_blk_len & 1)) { + acpi_ut_fadt_register_error ("(x)GPE0_BLK_LEN", + (u32) acpi_gbl_FADT->gpe0_blk_len, + ACPI_FADT_OFFSET (gpe0_blk_len)); + } + + if (acpi_gbl_FADT->xgpe1_blk.address && + (acpi_gbl_FADT->gpe1_blk_len & 1)) { + acpi_ut_fadt_register_error ("(x)GPE1_BLK_LEN", + (u32) acpi_gbl_FADT->gpe1_blk_len, + ACPI_FADT_OFFSET (gpe1_blk_len)); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: acpi_ut_terminate + * + * PARAMETERS: none + * + * RETURN: none + * + * DESCRIPTION: free global memory + * + ******************************************************************************/ + +void +acpi_ut_terminate (void) +{ + struct acpi_gpe_block_info *gpe_block; + struct acpi_gpe_block_info *next_gpe_block; + struct acpi_gpe_xrupt_info *gpe_xrupt_info; + struct acpi_gpe_xrupt_info *next_gpe_xrupt_info; + + + ACPI_FUNCTION_TRACE ("ut_terminate"); + + + /* Free global tables, etc. */ + + + /* Free global GPE blocks and related info structures */ + + gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head; + while (gpe_xrupt_info) { + gpe_block = gpe_xrupt_info->gpe_block_list_head; + while (gpe_block) { + next_gpe_block = gpe_block->next; + ACPI_MEM_FREE (gpe_block->event_info); + ACPI_MEM_FREE (gpe_block->register_info); + ACPI_MEM_FREE (gpe_block); + + gpe_block = next_gpe_block; + } + next_gpe_xrupt_info = gpe_xrupt_info->next; + ACPI_MEM_FREE (gpe_xrupt_info); + gpe_xrupt_info = next_gpe_xrupt_info; + } + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_subsystem_shutdown + * + * PARAMETERS: none + * + * RETURN: none + * + * DESCRIPTION: Shutdown the various subsystems. Don't delete the mutex + * objects here -- because the AML debugger may be still running. + * + ******************************************************************************/ + +void +acpi_ut_subsystem_shutdown (void) +{ + + ACPI_FUNCTION_TRACE ("ut_subsystem_shutdown"); + + /* Just exit if subsystem is already shutdown */ + + if (acpi_gbl_shutdown) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "ACPI Subsystem is already terminated\n")); + return_VOID; + } + + /* Subsystem appears active, go ahead and shut it down */ + + acpi_gbl_shutdown = TRUE; + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Shutting down ACPI Subsystem...\n")); + + /* Close the acpi_event Handling */ + + acpi_ev_terminate (); + + /* Close the Namespace */ + + acpi_ns_terminate (); + + /* Close the globals */ + + acpi_ut_terminate (); + + /* Purge the local caches */ + + (void) acpi_purge_cached_objects (); + + /* Debug only - display leftover memory allocation, if any */ + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + acpi_ut_dump_allocations (ACPI_UINT32_MAX, NULL); +#endif + + return_VOID; +} + + diff --git a/drivers/acpi/utilities/utmath.c b/drivers/acpi/utilities/utmath.c new file mode 100644 index 000000000000..2525c1a93547 --- /dev/null +++ b/drivers/acpi/utilities/utmath.c @@ -0,0 +1,333 @@ +/******************************************************************************* + * + * Module Name: utmath - Integer math support routines + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + + +#include <acpi/acpi.h> + + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utmath") + +/* + * Support for double-precision integer divide. This code is included here + * in order to support kernel environments where the double-precision math + * library is not available. + */ + +#ifndef ACPI_USE_NATIVE_DIVIDE +/******************************************************************************* + * + * FUNCTION: acpi_ut_short_divide + * + * PARAMETERS: Dividend - 64-bit dividend + * Divisor - 32-bit divisor + * out_quotient - Pointer to where the quotient is returned + * out_remainder - Pointer to where the remainder is returned + * + * RETURN: Status (Checks for divide-by-zero) + * + * DESCRIPTION: Perform a short (maximum 64 bits divided by 32 bits) + * divide and modulo. The result is a 64-bit quotient and a + * 32-bit remainder. + * + ******************************************************************************/ + +acpi_status +acpi_ut_short_divide ( + acpi_integer dividend, + u32 divisor, + acpi_integer *out_quotient, + u32 *out_remainder) +{ + union uint64_overlay dividend_ovl; + union uint64_overlay quotient; + u32 remainder32; + + + ACPI_FUNCTION_TRACE ("ut_short_divide"); + + + /* Always check for a zero divisor */ + + if (divisor == 0) { + ACPI_REPORT_ERROR (("acpi_ut_short_divide: Divide by zero\n")); + return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO); + } + + dividend_ovl.full = dividend; + + /* + * The quotient is 64 bits, the remainder is always 32 bits, + * and is generated by the second divide. + */ + ACPI_DIV_64_BY_32 (0, dividend_ovl.part.hi, divisor, + quotient.part.hi, remainder32); + ACPI_DIV_64_BY_32 (remainder32, dividend_ovl.part.lo, divisor, + quotient.part.lo, remainder32); + + /* Return only what was requested */ + + if (out_quotient) { + *out_quotient = quotient.full; + } + if (out_remainder) { + *out_remainder = remainder32; + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_divide + * + * PARAMETERS: in_dividend - Dividend + * in_divisor - Divisor + * out_quotient - Pointer to where the quotient is returned + * out_remainder - Pointer to where the remainder is returned + * + * RETURN: Status (Checks for divide-by-zero) + * + * DESCRIPTION: Perform a divide and modulo. + * + ******************************************************************************/ + +acpi_status +acpi_ut_divide ( + acpi_integer in_dividend, + acpi_integer in_divisor, + acpi_integer *out_quotient, + acpi_integer *out_remainder) +{ + union uint64_overlay dividend; + union uint64_overlay divisor; + union uint64_overlay quotient; + union uint64_overlay remainder; + union uint64_overlay normalized_dividend; + union uint64_overlay normalized_divisor; + u32 partial1; + union uint64_overlay partial2; + union uint64_overlay partial3; + + + ACPI_FUNCTION_TRACE ("ut_divide"); + + + /* Always check for a zero divisor */ + + if (in_divisor == 0) { + ACPI_REPORT_ERROR (("acpi_ut_divide: Divide by zero\n")); + return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO); + } + + divisor.full = in_divisor; + dividend.full = in_dividend; + if (divisor.part.hi == 0) { + /* + * 1) Simplest case is where the divisor is 32 bits, we can + * just do two divides + */ + remainder.part.hi = 0; + + /* + * The quotient is 64 bits, the remainder is always 32 bits, + * and is generated by the second divide. + */ + ACPI_DIV_64_BY_32 (0, dividend.part.hi, divisor.part.lo, + quotient.part.hi, partial1); + ACPI_DIV_64_BY_32 (partial1, dividend.part.lo, divisor.part.lo, + quotient.part.lo, remainder.part.lo); + } + + else { + /* + * 2) The general case where the divisor is a full 64 bits + * is more difficult + */ + quotient.part.hi = 0; + normalized_dividend = dividend; + normalized_divisor = divisor; + + /* Normalize the operands (shift until the divisor is < 32 bits) */ + + do { + ACPI_SHIFT_RIGHT_64 (normalized_divisor.part.hi, + normalized_divisor.part.lo); + ACPI_SHIFT_RIGHT_64 (normalized_dividend.part.hi, + normalized_dividend.part.lo); + + } while (normalized_divisor.part.hi != 0); + + /* Partial divide */ + + ACPI_DIV_64_BY_32 (normalized_dividend.part.hi, + normalized_dividend.part.lo, + normalized_divisor.part.lo, + quotient.part.lo, partial1); + + /* + * The quotient is always 32 bits, and simply requires adjustment. + * The 64-bit remainder must be generated. + */ + partial1 = quotient.part.lo * divisor.part.hi; + partial2.full = (acpi_integer) quotient.part.lo * divisor.part.lo; + partial3.full = (acpi_integer) partial2.part.hi + partial1; + + remainder.part.hi = partial3.part.lo; + remainder.part.lo = partial2.part.lo; + + if (partial3.part.hi == 0) { + if (partial3.part.lo >= dividend.part.hi) { + if (partial3.part.lo == dividend.part.hi) { + if (partial2.part.lo > dividend.part.lo) { + quotient.part.lo--; + remainder.full -= divisor.full; + } + } + else { + quotient.part.lo--; + remainder.full -= divisor.full; + } + } + + remainder.full = remainder.full - dividend.full; + remainder.part.hi = (u32) -((s32) remainder.part.hi); + remainder.part.lo = (u32) -((s32) remainder.part.lo); + + if (remainder.part.lo) { + remainder.part.hi--; + } + } + } + + /* Return only what was requested */ + + if (out_quotient) { + *out_quotient = quotient.full; + } + if (out_remainder) { + *out_remainder = remainder.full; + } + + return_ACPI_STATUS (AE_OK); +} + +#else + +/******************************************************************************* + * + * FUNCTION: acpi_ut_short_divide, acpi_ut_divide + * + * DESCRIPTION: Native versions of the ut_divide functions. Use these if either + * 1) The target is a 64-bit platform and therefore 64-bit + * integer math is supported directly by the machine. + * 2) The target is a 32-bit or 16-bit platform, and the + * double-precision integer math library is available to + * perform the divide. + * + ******************************************************************************/ + +acpi_status +acpi_ut_short_divide ( + acpi_integer in_dividend, + u32 divisor, + acpi_integer *out_quotient, + u32 *out_remainder) +{ + + ACPI_FUNCTION_TRACE ("ut_short_divide"); + + + /* Always check for a zero divisor */ + + if (divisor == 0) { + ACPI_REPORT_ERROR (("acpi_ut_short_divide: Divide by zero\n")); + return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO); + } + + /* Return only what was requested */ + + if (out_quotient) { + *out_quotient = in_dividend / divisor; + } + if (out_remainder) { + *out_remainder = (u32) in_dividend % divisor; + } + + return_ACPI_STATUS (AE_OK); +} + +acpi_status +acpi_ut_divide ( + acpi_integer in_dividend, + acpi_integer in_divisor, + acpi_integer *out_quotient, + acpi_integer *out_remainder) +{ + ACPI_FUNCTION_TRACE ("ut_divide"); + + + /* Always check for a zero divisor */ + + if (in_divisor == 0) { + ACPI_REPORT_ERROR (("acpi_ut_divide: Divide by zero\n")); + return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO); + } + + + /* Return only what was requested */ + + if (out_quotient) { + *out_quotient = in_dividend / in_divisor; + } + if (out_remainder) { + *out_remainder = in_dividend % in_divisor; + } + + return_ACPI_STATUS (AE_OK); +} + +#endif + + diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c new file mode 100644 index 000000000000..f6598547389b --- /dev/null +++ b/drivers/acpi/utilities/utmisc.c @@ -0,0 +1,1516 @@ +/******************************************************************************* + * + * Module Name: utmisc - common utility procedures + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + + +#include <acpi/acpi.h> +#include <acpi/acnamesp.h> + + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utmisc") + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_print_string + * + * PARAMETERS: String - Null terminated ASCII string + * + * RETURN: None + * + * DESCRIPTION: Dump an ASCII string with support for ACPI-defined escape + * sequences. + * + ******************************************************************************/ + +void +acpi_ut_print_string ( + char *string, + u8 max_length) +{ + u32 i; + + + if (!string) { + acpi_os_printf ("<\"NULL STRING PTR\">"); + return; + } + + acpi_os_printf ("\""); + for (i = 0; string[i] && (i < max_length); i++) { + /* Escape sequences */ + + switch (string[i]) { + case 0x07: + acpi_os_printf ("\\a"); /* BELL */ + break; + + case 0x08: + acpi_os_printf ("\\b"); /* BACKSPACE */ + break; + + case 0x0C: + acpi_os_printf ("\\f"); /* FORMFEED */ + break; + + case 0x0A: + acpi_os_printf ("\\n"); /* LINEFEED */ + break; + + case 0x0D: + acpi_os_printf ("\\r"); /* CARRIAGE RETURN*/ + break; + + case 0x09: + acpi_os_printf ("\\t"); /* HORIZONTAL TAB */ + break; + + case 0x0B: + acpi_os_printf ("\\v"); /* VERTICAL TAB */ + break; + + case '\'': /* Single Quote */ + case '\"': /* Double Quote */ + case '\\': /* Backslash */ + acpi_os_printf ("\\%c", (int) string[i]); + break; + + default: + + /* Check for printable character or hex escape */ + + if (ACPI_IS_PRINT (string[i])) + { + /* This is a normal character */ + + acpi_os_printf ("%c", (int) string[i]); + } + else + { + /* All others will be Hex escapes */ + + acpi_os_printf ("\\x%2.2X", (s32) string[i]); + } + break; + } + } + acpi_os_printf ("\""); + + if (i == max_length && string[i]) { + acpi_os_printf ("..."); + } +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_dword_byte_swap + * + * PARAMETERS: Value - Value to be converted + * + * DESCRIPTION: Convert a 32-bit value to big-endian (swap the bytes) + * + ******************************************************************************/ + +u32 +acpi_ut_dword_byte_swap ( + u32 value) +{ + union { + u32 value; + u8 bytes[4]; + } out; + + union { + u32 value; + u8 bytes[4]; + } in; + + + ACPI_FUNCTION_ENTRY (); + + + in.value = value; + + out.bytes[0] = in.bytes[3]; + out.bytes[1] = in.bytes[2]; + out.bytes[2] = in.bytes[1]; + out.bytes[3] = in.bytes[0]; + + return (out.value); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_set_integer_width + * + * PARAMETERS: Revision From DSDT header + * + * RETURN: None + * + * DESCRIPTION: Set the global integer bit width based upon the revision + * of the DSDT. For Revision 1 and 0, Integers are 32 bits. + * For Revision 2 and above, Integers are 64 bits. Yes, this + * makes a difference. + * + ******************************************************************************/ + +void +acpi_ut_set_integer_width ( + u8 revision) +{ + + if (revision <= 1) { + acpi_gbl_integer_bit_width = 32; + acpi_gbl_integer_nybble_width = 8; + acpi_gbl_integer_byte_width = 4; + } + else { + acpi_gbl_integer_bit_width = 64; + acpi_gbl_integer_nybble_width = 16; + acpi_gbl_integer_byte_width = 8; + } +} + + +#ifdef ACPI_DEBUG_OUTPUT +/******************************************************************************* + * + * FUNCTION: acpi_ut_display_init_pathname + * + * PARAMETERS: obj_handle - Handle whose pathname will be displayed + * Path - Additional path string to be appended. + * (NULL if no extra path) + * + * RETURN: acpi_status + * + * DESCRIPTION: Display full pathname of an object, DEBUG ONLY + * + ******************************************************************************/ + +void +acpi_ut_display_init_pathname ( + u8 type, + struct acpi_namespace_node *obj_handle, + char *path) +{ + acpi_status status; + struct acpi_buffer buffer; + + + ACPI_FUNCTION_ENTRY (); + + + /* Only print the path if the appropriate debug level is enabled */ + + if (!(acpi_dbg_level & ACPI_LV_INIT_NAMES)) { + return; + } + + /* Get the full pathname to the node */ + + buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; + status = acpi_ns_handle_to_pathname (obj_handle, &buffer); + if (ACPI_FAILURE (status)) { + return; + } + + /* Print what we're doing */ + + switch (type) { + case ACPI_TYPE_METHOD: + acpi_os_printf ("Executing "); + break; + + default: + acpi_os_printf ("Initializing "); + break; + } + + /* Print the object type and pathname */ + + acpi_os_printf ("%-12s %s", acpi_ut_get_type_name (type), (char *) buffer.pointer); + + /* Extra path is used to append names like _STA, _INI, etc. */ + + if (path) { + acpi_os_printf (".%s", path); + } + acpi_os_printf ("\n"); + + ACPI_MEM_FREE (buffer.pointer); +} +#endif + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_valid_acpi_name + * + * PARAMETERS: Character - The character to be examined + * + * RETURN: 1 if Character may appear in a name, else 0 + * + * DESCRIPTION: Check for a valid ACPI name. Each character must be one of: + * 1) Upper case alpha + * 2) numeric + * 3) underscore + * + ******************************************************************************/ + +u8 +acpi_ut_valid_acpi_name ( + u32 name) +{ + char *name_ptr = (char *) &name; + char character; + acpi_native_uint i; + + + ACPI_FUNCTION_ENTRY (); + + + for (i = 0; i < ACPI_NAME_SIZE; i++) { + character = *name_ptr; + name_ptr++; + + if (!((character == '_') || + (character >= 'A' && character <= 'Z') || + (character >= '0' && character <= '9'))) { + return (FALSE); + } + } + + return (TRUE); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_valid_acpi_character + * + * PARAMETERS: Character - The character to be examined + * + * RETURN: 1 if Character may appear in a name, else 0 + * + * DESCRIPTION: Check for a printable character + * + ******************************************************************************/ + +u8 +acpi_ut_valid_acpi_character ( + char character) +{ + + ACPI_FUNCTION_ENTRY (); + + return ((u8) ((character == '_') || + (character >= 'A' && character <= 'Z') || + (character >= '0' && character <= '9'))); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strtoul64 + * + * PARAMETERS: String - Null terminated string + * Base - Radix of the string: 10, 16, or ACPI_ANY_BASE + * ret_integer - Where the converted integer is returned + * + * RETURN: Status and Converted value + * + * DESCRIPTION: Convert a string into an unsigned value. + * NOTE: Does not support Octal strings, not needed. + * + ******************************************************************************/ + +acpi_status +acpi_ut_strtoul64 ( + char *string, + u32 base, + acpi_integer *ret_integer) +{ + u32 this_digit = 0; + acpi_integer return_value = 0; + acpi_integer quotient; + + + ACPI_FUNCTION_TRACE ("ut_stroul64"); + + + if ((!string) || !(*string)) { + goto error_exit; + } + + switch (base) { + case ACPI_ANY_BASE: + case 10: + case 16: + break; + + default: + /* Invalid Base */ + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Skip over any white space in the buffer */ + + while (ACPI_IS_SPACE (*string) || *string == '\t') { + string++; + } + + /* + * If the input parameter Base is zero, then we need to + * determine if it is decimal or hexadecimal: + */ + if (base == 0) { + if ((*string == '0') && + (ACPI_TOLOWER (*(string + 1)) == 'x')) { + base = 16; + string += 2; + } + else { + base = 10; + } + } + + /* + * For hexadecimal base, skip over the leading + * 0 or 0x, if they are present. + */ + if ((base == 16) && + (*string == '0') && + (ACPI_TOLOWER (*(string + 1)) == 'x')) { + string += 2; + } + + /* Any string left? */ + + if (!(*string)) { + goto error_exit; + } + + /* Main loop: convert the string to a 64-bit integer */ + + while (*string) { + if (ACPI_IS_DIGIT (*string)) { + /* Convert ASCII 0-9 to Decimal value */ + + this_digit = ((u8) *string) - '0'; + } + else { + if (base == 10) { + /* Digit is out of range */ + + goto error_exit; + } + + this_digit = (u8) ACPI_TOUPPER (*string); + if (ACPI_IS_XDIGIT ((char) this_digit)) { + /* Convert ASCII Hex char to value */ + + this_digit = this_digit - 'A' + 10; + } + else { + /* + * We allow non-hex chars, just stop now, same as end-of-string. + * See ACPI spec, string-to-integer conversion. + */ + break; + } + } + + /* Divide the digit into the correct position */ + + (void) acpi_ut_short_divide ((ACPI_INTEGER_MAX - (acpi_integer) this_digit), + base, "ient, NULL); + if (return_value > quotient) { + goto error_exit; + } + + return_value *= base; + return_value += this_digit; + string++; + } + + /* All done, normal exit */ + + *ret_integer = return_value; + return_ACPI_STATUS (AE_OK); + + +error_exit: + /* Base was set/validated above */ + + if (base == 10) { + return_ACPI_STATUS (AE_BAD_DECIMAL_CONSTANT); + } + else { + return_ACPI_STATUS (AE_BAD_HEX_CONSTANT); + } +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strupr + * + * PARAMETERS: src_string - The source string to convert to + * + * RETURN: src_string + * + * DESCRIPTION: Convert string to uppercase + * + ******************************************************************************/ +#ifdef ACPI_FUTURE_USAGE +char * +acpi_ut_strupr ( + char *src_string) +{ + char *string; + + + ACPI_FUNCTION_ENTRY (); + + + /* Walk entire string, uppercasing the letters */ + + for (string = src_string; *string; ) { + *string = (char) ACPI_TOUPPER (*string); + string++; + } + + return (src_string); +} +#endif /* ACPI_FUTURE_USAGE */ + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_mutex_initialize + * + * PARAMETERS: None. + * + * RETURN: Status + * + * DESCRIPTION: Create the system mutex objects. + * + ******************************************************************************/ + +acpi_status +acpi_ut_mutex_initialize ( + void) +{ + u32 i; + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ut_mutex_initialize"); + + + /* + * Create each of the predefined mutex objects + */ + for (i = 0; i < NUM_MUTEX; i++) { + status = acpi_ut_create_mutex (i); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + status = acpi_os_create_lock (&acpi_gbl_gpe_lock); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_mutex_terminate + * + * PARAMETERS: None. + * + * RETURN: None. + * + * DESCRIPTION: Delete all of the system mutex objects. + * + ******************************************************************************/ + +void +acpi_ut_mutex_terminate ( + void) +{ + u32 i; + + + ACPI_FUNCTION_TRACE ("ut_mutex_terminate"); + + + /* + * Delete each predefined mutex object + */ + for (i = 0; i < NUM_MUTEX; i++) { + (void) acpi_ut_delete_mutex (i); + } + + acpi_os_delete_lock (acpi_gbl_gpe_lock); + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_create_mutex + * + * PARAMETERS: mutex_iD - ID of the mutex to be created + * + * RETURN: Status + * + * DESCRIPTION: Create a mutex object. + * + ******************************************************************************/ + +acpi_status +acpi_ut_create_mutex ( + acpi_mutex_handle mutex_id) +{ + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE_U32 ("ut_create_mutex", mutex_id); + + + if (mutex_id > MAX_MUTEX) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + if (!acpi_gbl_mutex_info[mutex_id].mutex) { + status = acpi_os_create_semaphore (1, 1, + &acpi_gbl_mutex_info[mutex_id].mutex); + acpi_gbl_mutex_info[mutex_id].owner_id = ACPI_MUTEX_NOT_ACQUIRED; + acpi_gbl_mutex_info[mutex_id].use_count = 0; + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_delete_mutex + * + * PARAMETERS: mutex_iD - ID of the mutex to be deleted + * + * RETURN: Status + * + * DESCRIPTION: Delete a mutex object. + * + ******************************************************************************/ + +acpi_status +acpi_ut_delete_mutex ( + acpi_mutex_handle mutex_id) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE_U32 ("ut_delete_mutex", mutex_id); + + + if (mutex_id > MAX_MUTEX) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + status = acpi_os_delete_semaphore (acpi_gbl_mutex_info[mutex_id].mutex); + + acpi_gbl_mutex_info[mutex_id].mutex = NULL; + acpi_gbl_mutex_info[mutex_id].owner_id = ACPI_MUTEX_NOT_ACQUIRED; + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_acquire_mutex + * + * PARAMETERS: mutex_iD - ID of the mutex to be acquired + * + * RETURN: Status + * + * DESCRIPTION: Acquire a mutex object. + * + ******************************************************************************/ + +acpi_status +acpi_ut_acquire_mutex ( + acpi_mutex_handle mutex_id) +{ + acpi_status status; + u32 this_thread_id; + + + ACPI_FUNCTION_NAME ("ut_acquire_mutex"); + + + if (mutex_id > MAX_MUTEX) { + return (AE_BAD_PARAMETER); + } + + this_thread_id = acpi_os_get_thread_id (); + +#ifdef ACPI_MUTEX_DEBUG + { + u32 i; + /* + * Mutex debug code, for internal debugging only. + * + * Deadlock prevention. Check if this thread owns any mutexes of value + * greater than or equal to this one. If so, the thread has violated + * the mutex ordering rule. This indicates a coding error somewhere in + * the ACPI subsystem code. + */ + for (i = mutex_id; i < MAX_MUTEX; i++) { + if (acpi_gbl_mutex_info[i].owner_id == this_thread_id) { + if (i == mutex_id) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Mutex [%s] already acquired by this thread [%X]\n", + acpi_ut_get_mutex_name (mutex_id), this_thread_id)); + + return (AE_ALREADY_ACQUIRED); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Invalid acquire order: Thread %X owns [%s], wants [%s]\n", + this_thread_id, acpi_ut_get_mutex_name (i), + acpi_ut_get_mutex_name (mutex_id))); + + return (AE_ACQUIRE_DEADLOCK); + } + } + } +#endif + + ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, + "Thread %X attempting to acquire Mutex [%s]\n", + this_thread_id, acpi_ut_get_mutex_name (mutex_id))); + + status = acpi_os_wait_semaphore (acpi_gbl_mutex_info[mutex_id].mutex, + 1, ACPI_WAIT_FOREVER); + if (ACPI_SUCCESS (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %X acquired Mutex [%s]\n", + this_thread_id, acpi_ut_get_mutex_name (mutex_id))); + + acpi_gbl_mutex_info[mutex_id].use_count++; + acpi_gbl_mutex_info[mutex_id].owner_id = this_thread_id; + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Thread %X could not acquire Mutex [%s] %s\n", + this_thread_id, acpi_ut_get_mutex_name (mutex_id), + acpi_format_exception (status))); + } + + return (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_release_mutex + * + * PARAMETERS: mutex_iD - ID of the mutex to be released + * + * RETURN: Status + * + * DESCRIPTION: Release a mutex object. + * + ******************************************************************************/ + +acpi_status +acpi_ut_release_mutex ( + acpi_mutex_handle mutex_id) +{ + acpi_status status; + u32 i; + u32 this_thread_id; + + + ACPI_FUNCTION_NAME ("ut_release_mutex"); + + + this_thread_id = acpi_os_get_thread_id (); + ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, + "Thread %X releasing Mutex [%s]\n", this_thread_id, + acpi_ut_get_mutex_name (mutex_id))); + + if (mutex_id > MAX_MUTEX) { + return (AE_BAD_PARAMETER); + } + + /* + * Mutex must be acquired in order to release it! + */ + if (acpi_gbl_mutex_info[mutex_id].owner_id == ACPI_MUTEX_NOT_ACQUIRED) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Mutex [%s] is not acquired, cannot release\n", + acpi_ut_get_mutex_name (mutex_id))); + + return (AE_NOT_ACQUIRED); + } + + /* + * Deadlock prevention. Check if this thread owns any mutexes of value + * greater than this one. If so, the thread has violated the mutex + * ordering rule. This indicates a coding error somewhere in + * the ACPI subsystem code. + */ + for (i = mutex_id; i < MAX_MUTEX; i++) { + if (acpi_gbl_mutex_info[i].owner_id == this_thread_id) { + if (i == mutex_id) { + continue; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Invalid release order: owns [%s], releasing [%s]\n", + acpi_ut_get_mutex_name (i), acpi_ut_get_mutex_name (mutex_id))); + + return (AE_RELEASE_DEADLOCK); + } + } + + /* Mark unlocked FIRST */ + + acpi_gbl_mutex_info[mutex_id].owner_id = ACPI_MUTEX_NOT_ACQUIRED; + + status = acpi_os_signal_semaphore (acpi_gbl_mutex_info[mutex_id].mutex, 1); + + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Thread %X could not release Mutex [%s] %s\n", + this_thread_id, acpi_ut_get_mutex_name (mutex_id), + acpi_format_exception (status))); + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %X released Mutex [%s]\n", + this_thread_id, acpi_ut_get_mutex_name (mutex_id))); + } + + return (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_create_update_state_and_push + * + * PARAMETERS: *Object - Object to be added to the new state + * Action - Increment/Decrement + * state_list - List the state will be added to + * + * RETURN: None + * + * DESCRIPTION: Create a new state and push it + * + ******************************************************************************/ + +acpi_status +acpi_ut_create_update_state_and_push ( + union acpi_operand_object *object, + u16 action, + union acpi_generic_state **state_list) +{ + union acpi_generic_state *state; + + + ACPI_FUNCTION_ENTRY (); + + + /* Ignore null objects; these are expected */ + + if (!object) { + return (AE_OK); + } + + state = acpi_ut_create_update_state (object, action); + if (!state) { + return (AE_NO_MEMORY); + } + + acpi_ut_push_generic_state (state_list, state); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_create_pkg_state_and_push + * + * PARAMETERS: *Object - Object to be added to the new state + * Action - Increment/Decrement + * state_list - List the state will be added to + * + * RETURN: None + * + * DESCRIPTION: Create a new state and push it + * + ******************************************************************************/ +#ifdef ACPI_FUTURE_USAGE +acpi_status +acpi_ut_create_pkg_state_and_push ( + void *internal_object, + void *external_object, + u16 index, + union acpi_generic_state **state_list) +{ + union acpi_generic_state *state; + + + ACPI_FUNCTION_ENTRY (); + + + state = acpi_ut_create_pkg_state (internal_object, external_object, index); + if (!state) { + return (AE_NO_MEMORY); + } + + acpi_ut_push_generic_state (state_list, state); + return (AE_OK); +} +#endif /* ACPI_FUTURE_USAGE */ + +/******************************************************************************* + * + * FUNCTION: acpi_ut_push_generic_state + * + * PARAMETERS: list_head - Head of the state stack + * State - State object to push + * + * RETURN: Status + * + * DESCRIPTION: Push a state object onto a state stack + * + ******************************************************************************/ + +void +acpi_ut_push_generic_state ( + union acpi_generic_state **list_head, + union acpi_generic_state *state) +{ + ACPI_FUNCTION_TRACE ("ut_push_generic_state"); + + + /* Push the state object onto the front of the list (stack) */ + + state->common.next = *list_head; + *list_head = state; + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_pop_generic_state + * + * PARAMETERS: list_head - Head of the state stack + * + * RETURN: Status + * + * DESCRIPTION: Pop a state object from a state stack + * + ******************************************************************************/ + +union acpi_generic_state * +acpi_ut_pop_generic_state ( + union acpi_generic_state **list_head) +{ + union acpi_generic_state *state; + + + ACPI_FUNCTION_TRACE ("ut_pop_generic_state"); + + + /* Remove the state object at the head of the list (stack) */ + + state = *list_head; + if (state) { + /* Update the list head */ + + *list_head = state->common.next; + } + + return_PTR (state); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_create_generic_state + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Create a generic state object. Attempt to obtain one from + * the global state cache; If none available, create a new one. + * + ******************************************************************************/ + +union acpi_generic_state * +acpi_ut_create_generic_state (void) +{ + union acpi_generic_state *state; + + + ACPI_FUNCTION_ENTRY (); + + + state = acpi_ut_acquire_from_cache (ACPI_MEM_LIST_STATE); + + /* Initialize */ + + if (state) { + state->common.data_type = ACPI_DESC_TYPE_STATE; + } + + return (state); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_create_thread_state + * + * PARAMETERS: None + * + * RETURN: Thread State + * + * DESCRIPTION: Create a "Thread State" - a flavor of the generic state used + * to track per-thread info during method execution + * + ******************************************************************************/ + +struct acpi_thread_state * +acpi_ut_create_thread_state ( + void) +{ + union acpi_generic_state *state; + + + ACPI_FUNCTION_TRACE ("ut_create_thread_state"); + + + /* Create the generic state object */ + + state = acpi_ut_create_generic_state (); + if (!state) { + return_PTR (NULL); + } + + /* Init fields specific to the update struct */ + + state->common.data_type = ACPI_DESC_TYPE_STATE_THREAD; + state->thread.thread_id = acpi_os_get_thread_id (); + + return_PTR ((struct acpi_thread_state *) state); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_create_update_state + * + * PARAMETERS: Object - Initial Object to be installed in the + * state + * Action - Update action to be performed + * + * RETURN: Status + * + * DESCRIPTION: Create an "Update State" - a flavor of the generic state used + * to update reference counts and delete complex objects such + * as packages. + * + ******************************************************************************/ + +union acpi_generic_state * +acpi_ut_create_update_state ( + union acpi_operand_object *object, + u16 action) +{ + union acpi_generic_state *state; + + + ACPI_FUNCTION_TRACE_PTR ("ut_create_update_state", object); + + + /* Create the generic state object */ + + state = acpi_ut_create_generic_state (); + if (!state) { + return_PTR (NULL); + } + + /* Init fields specific to the update struct */ + + state->common.data_type = ACPI_DESC_TYPE_STATE_UPDATE; + state->update.object = object; + state->update.value = action; + + return_PTR (state); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_create_pkg_state + * + * PARAMETERS: Object - Initial Object to be installed in the + * state + * Action - Update action to be performed + * + * RETURN: Status + * + * DESCRIPTION: Create a "Package State" + * + ******************************************************************************/ + +union acpi_generic_state * +acpi_ut_create_pkg_state ( + void *internal_object, + void *external_object, + u16 index) +{ + union acpi_generic_state *state; + + + ACPI_FUNCTION_TRACE_PTR ("ut_create_pkg_state", internal_object); + + + /* Create the generic state object */ + + state = acpi_ut_create_generic_state (); + if (!state) { + return_PTR (NULL); + } + + /* Init fields specific to the update struct */ + + state->common.data_type = ACPI_DESC_TYPE_STATE_PACKAGE; + state->pkg.source_object = (union acpi_operand_object *) internal_object; + state->pkg.dest_object = external_object; + state->pkg.index = index; + state->pkg.num_packages = 1; + + return_PTR (state); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_create_control_state + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Create a "Control State" - a flavor of the generic state used + * to support nested IF/WHILE constructs in the AML. + * + ******************************************************************************/ + +union acpi_generic_state * +acpi_ut_create_control_state ( + void) +{ + union acpi_generic_state *state; + + + ACPI_FUNCTION_TRACE ("ut_create_control_state"); + + + /* Create the generic state object */ + + state = acpi_ut_create_generic_state (); + if (!state) { + return_PTR (NULL); + } + + /* Init fields specific to the control struct */ + + state->common.data_type = ACPI_DESC_TYPE_STATE_CONTROL; + state->common.state = ACPI_CONTROL_CONDITIONAL_EXECUTING; + + return_PTR (state); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_delete_generic_state + * + * PARAMETERS: State - The state object to be deleted + * + * RETURN: Status + * + * DESCRIPTION: Put a state object back into the global state cache. The object + * is not actually freed at this time. + * + ******************************************************************************/ + +void +acpi_ut_delete_generic_state ( + union acpi_generic_state *state) +{ + ACPI_FUNCTION_TRACE ("ut_delete_generic_state"); + + + acpi_ut_release_to_cache (ACPI_MEM_LIST_STATE, state); + return_VOID; +} + + +#ifdef ACPI_ENABLE_OBJECT_CACHE +/******************************************************************************* + * + * FUNCTION: acpi_ut_delete_generic_state_cache + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Purge the global state object cache. Used during subsystem + * termination. + * + ******************************************************************************/ + +void +acpi_ut_delete_generic_state_cache ( + void) +{ + ACPI_FUNCTION_TRACE ("ut_delete_generic_state_cache"); + + + acpi_ut_delete_generic_cache (ACPI_MEM_LIST_STATE); + return_VOID; +} +#endif + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_walk_package_tree + * + * PARAMETERS: obj_desc - The Package object on which to resolve refs + * + * RETURN: Status + * + * DESCRIPTION: Walk through a package + * + ******************************************************************************/ + +acpi_status +acpi_ut_walk_package_tree ( + union acpi_operand_object *source_object, + void *target_object, + acpi_pkg_callback walk_callback, + void *context) +{ + acpi_status status = AE_OK; + union acpi_generic_state *state_list = NULL; + union acpi_generic_state *state; + u32 this_index; + union acpi_operand_object *this_source_obj; + + + ACPI_FUNCTION_TRACE ("ut_walk_package_tree"); + + + state = acpi_ut_create_pkg_state (source_object, target_object, 0); + if (!state) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + while (state) { + /* Get one element of the package */ + + this_index = state->pkg.index; + this_source_obj = (union acpi_operand_object *) + state->pkg.source_object->package.elements[this_index]; + + /* + * Check for: + * 1) An uninitialized package element. It is completely + * legal to declare a package and leave it uninitialized + * 2) Not an internal object - can be a namespace node instead + * 3) Any type other than a package. Packages are handled in else + * case below. + */ + if ((!this_source_obj) || + (ACPI_GET_DESCRIPTOR_TYPE (this_source_obj) != ACPI_DESC_TYPE_OPERAND) || + (ACPI_GET_OBJECT_TYPE (this_source_obj) != ACPI_TYPE_PACKAGE)) { + status = walk_callback (ACPI_COPY_TYPE_SIMPLE, this_source_obj, + state, context); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + state->pkg.index++; + while (state->pkg.index >= state->pkg.source_object->package.count) { + /* + * We've handled all of the objects at this level, This means + * that we have just completed a package. That package may + * have contained one or more packages itself. + * + * Delete this state and pop the previous state (package). + */ + acpi_ut_delete_generic_state (state); + state = acpi_ut_pop_generic_state (&state_list); + + /* Finished when there are no more states */ + + if (!state) { + /* + * We have handled all of the objects in the top level + * package just add the length of the package objects + * and exit + */ + return_ACPI_STATUS (AE_OK); + } + + /* + * Go back up a level and move the index past the just + * completed package object. + */ + state->pkg.index++; + } + } + else { + /* This is a subobject of type package */ + + status = walk_callback (ACPI_COPY_TYPE_PACKAGE, this_source_obj, + state, context); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* + * Push the current state and create a new one + * The callback above returned a new target package object. + */ + acpi_ut_push_generic_state (&state_list, state); + state = acpi_ut_create_pkg_state (this_source_obj, + state->pkg.this_target_obj, 0); + if (!state) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + } + } + + /* We should never get here */ + + return_ACPI_STATUS (AE_AML_INTERNAL); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_generate_checksum + * + * PARAMETERS: Buffer - Buffer to be scanned + * Length - number of bytes to examine + * + * RETURN: checksum + * + * DESCRIPTION: Generate a checksum on a raw buffer + * + ******************************************************************************/ + +u8 +acpi_ut_generate_checksum ( + u8 *buffer, + u32 length) +{ + u32 i; + signed char sum = 0; + + + for (i = 0; i < length; i++) { + sum = (signed char) (sum + buffer[i]); + } + + return ((u8) (0 - sum)); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_get_resource_end_tag + * + * PARAMETERS: obj_desc - The resource template buffer object + * + * RETURN: Pointer to the end tag + * + * DESCRIPTION: Find the END_TAG resource descriptor in a resource template + * + ******************************************************************************/ + + +u8 * +acpi_ut_get_resource_end_tag ( + union acpi_operand_object *obj_desc) +{ + u8 buffer_byte; + u8 *buffer; + u8 *end_buffer; + + + buffer = obj_desc->buffer.pointer; + end_buffer = buffer + obj_desc->buffer.length; + + while (buffer < end_buffer) { + buffer_byte = *buffer; + if (buffer_byte & ACPI_RDESC_TYPE_MASK) { + /* Large Descriptor - Length is next 2 bytes */ + + buffer += ((*(buffer+1) | (*(buffer+2) << 8)) + 3); + } + else { + /* Small Descriptor. End Tag will be found here */ + + if ((buffer_byte & ACPI_RDESC_SMALL_MASK) == ACPI_RDESC_TYPE_END_TAG) { + /* Found the end tag descriptor, all done. */ + + return (buffer); + } + + /* Length is in the header */ + + buffer += ((buffer_byte & 0x07) + 1); + } + } + + /* End tag not found */ + + return (NULL); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_report_error + * + * PARAMETERS: module_name - Caller's module name (for error output) + * line_number - Caller's line number (for error output) + * component_id - Caller's component ID (for error output) + * Message - Error message to use on failure + * + * RETURN: None + * + * DESCRIPTION: Print error message + * + ******************************************************************************/ + +void +acpi_ut_report_error ( + char *module_name, + u32 line_number, + u32 component_id) +{ + + + acpi_os_printf ("%8s-%04d: *** Error: ", module_name, line_number); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_report_warning + * + * PARAMETERS: module_name - Caller's module name (for error output) + * line_number - Caller's line number (for error output) + * component_id - Caller's component ID (for error output) + * Message - Error message to use on failure + * + * RETURN: None + * + * DESCRIPTION: Print warning message + * + ******************************************************************************/ + +void +acpi_ut_report_warning ( + char *module_name, + u32 line_number, + u32 component_id) +{ + + acpi_os_printf ("%8s-%04d: *** Warning: ", module_name, line_number); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_report_info + * + * PARAMETERS: module_name - Caller's module name (for error output) + * line_number - Caller's line number (for error output) + * component_id - Caller's component ID (for error output) + * Message - Error message to use on failure + * + * RETURN: None + * + * DESCRIPTION: Print information message + * + ******************************************************************************/ + +void +acpi_ut_report_info ( + char *module_name, + u32 line_number, + u32 component_id) +{ + + acpi_os_printf ("%8s-%04d: *** Info: ", module_name, line_number); +} + + diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/utilities/utobject.c new file mode 100644 index 000000000000..9ee40a484e07 --- /dev/null +++ b/drivers/acpi/utilities/utobject.c @@ -0,0 +1,671 @@ +/****************************************************************************** + * + * Module Name: utobject - ACPI object create/delete/size/cache routines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + + +#include <acpi/acpi.h> +#include <acpi/acnamesp.h> +#include <acpi/amlcode.h> + + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utobject") + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_create_internal_object_dbg + * + * PARAMETERS: module_name - Source file name of caller + * line_number - Line number of caller + * component_id - Component type of caller + * Type - ACPI Type of the new object + * + * RETURN: Object - The new object. Null on failure + * + * DESCRIPTION: Create and initialize a new internal object. + * + * NOTE: We always allocate the worst-case object descriptor because + * these objects are cached, and we want them to be + * one-size-satisifies-any-request. This in itself may not be + * the most memory efficient, but the efficiency of the object + * cache should more than make up for this! + * + ******************************************************************************/ + +union acpi_operand_object * +acpi_ut_create_internal_object_dbg ( + char *module_name, + u32 line_number, + u32 component_id, + acpi_object_type type) +{ + union acpi_operand_object *object; + union acpi_operand_object *second_object; + + + ACPI_FUNCTION_TRACE_STR ("ut_create_internal_object_dbg", acpi_ut_get_type_name (type)); + + + /* Allocate the raw object descriptor */ + + object = acpi_ut_allocate_object_desc_dbg (module_name, line_number, component_id); + if (!object) { + return_PTR (NULL); + } + + switch (type) { + case ACPI_TYPE_REGION: + case ACPI_TYPE_BUFFER_FIELD: + + /* These types require a secondary object */ + + second_object = acpi_ut_allocate_object_desc_dbg (module_name, line_number, component_id); + if (!second_object) { + acpi_ut_delete_object_desc (object); + return_PTR (NULL); + } + + second_object->common.type = ACPI_TYPE_LOCAL_EXTRA; + second_object->common.reference_count = 1; + + /* Link the second object to the first */ + + object->common.next_object = second_object; + break; + + default: + /* All others have no secondary object */ + break; + } + + /* Save the object type in the object descriptor */ + + object->common.type = (u8) type; + + /* Init the reference count */ + + object->common.reference_count = 1; + + /* Any per-type initialization should go here */ + + return_PTR (object); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_create_buffer_object + * + * PARAMETERS: buffer_size - Size of buffer to be created + * + * RETURN: Pointer to a new Buffer object + * + * DESCRIPTION: Create a fully initialized buffer object + * + ******************************************************************************/ + +union acpi_operand_object * +acpi_ut_create_buffer_object ( + acpi_size buffer_size) +{ + union acpi_operand_object *buffer_desc; + u8 *buffer = NULL; + + + ACPI_FUNCTION_TRACE_U32 ("ut_create_buffer_object", buffer_size); + + + /* Create a new Buffer object */ + + buffer_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER); + if (!buffer_desc) { + return_PTR (NULL); + } + + /* Create an actual buffer only if size > 0 */ + + if (buffer_size > 0) { + /* Allocate the actual buffer */ + + buffer = ACPI_MEM_CALLOCATE (buffer_size); + if (!buffer) { + ACPI_REPORT_ERROR (("create_buffer: could not allocate size %X\n", + (u32) buffer_size)); + acpi_ut_remove_reference (buffer_desc); + return_PTR (NULL); + } + } + + /* Complete buffer object initialization */ + + buffer_desc->buffer.flags |= AOPOBJ_DATA_VALID; + buffer_desc->buffer.pointer = buffer; + buffer_desc->buffer.length = (u32) buffer_size; + + /* Return the new buffer descriptor */ + + return_PTR (buffer_desc); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_create_string_object + * + * PARAMETERS: string_size - Size of string to be created. Does not + * include NULL terminator, this is added + * automatically. + * + * RETURN: Pointer to a new String object + * + * DESCRIPTION: Create a fully initialized string object + * + ******************************************************************************/ + +union acpi_operand_object * +acpi_ut_create_string_object ( + acpi_size string_size) +{ + union acpi_operand_object *string_desc; + char *string; + + + ACPI_FUNCTION_TRACE_U32 ("ut_create_string_object", string_size); + + + /* Create a new String object */ + + string_desc = acpi_ut_create_internal_object (ACPI_TYPE_STRING); + if (!string_desc) { + return_PTR (NULL); + } + + /* + * Allocate the actual string buffer -- (Size + 1) for NULL terminator. + * NOTE: Zero-length strings are NULL terminated + */ + string = ACPI_MEM_CALLOCATE (string_size + 1); + if (!string) { + ACPI_REPORT_ERROR (("create_string: could not allocate size %X\n", + (u32) string_size)); + acpi_ut_remove_reference (string_desc); + return_PTR (NULL); + } + + /* Complete string object initialization */ + + string_desc->string.pointer = string; + string_desc->string.length = (u32) string_size; + + /* Return the new string descriptor */ + + return_PTR (string_desc); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_valid_internal_object + * + * PARAMETERS: Object - Object to be validated + * + * RETURN: Validate a pointer to be an union acpi_operand_object + * + ******************************************************************************/ + +u8 +acpi_ut_valid_internal_object ( + void *object) +{ + + ACPI_FUNCTION_NAME ("ut_valid_internal_object"); + + + /* Check for a null pointer */ + + if (!object) { + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "**** Null Object Ptr\n")); + return (FALSE); + } + + /* Check the descriptor type field */ + + switch (ACPI_GET_DESCRIPTOR_TYPE (object)) { + case ACPI_DESC_TYPE_OPERAND: + + /* The object appears to be a valid union acpi_operand_object */ + + return (TRUE); + + default: + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "%p is not not an ACPI operand obj [%s]\n", + object, acpi_ut_get_descriptor_name (object))); + break; + } + + return (FALSE); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_allocate_object_desc_dbg + * + * PARAMETERS: module_name - Caller's module name (for error output) + * line_number - Caller's line number (for error output) + * component_id - Caller's component ID (for error output) + * + * RETURN: Pointer to newly allocated object descriptor. Null on error + * + * DESCRIPTION: Allocate a new object descriptor. Gracefully handle + * error conditions. + * + ******************************************************************************/ + +void * +acpi_ut_allocate_object_desc_dbg ( + char *module_name, + u32 line_number, + u32 component_id) +{ + union acpi_operand_object *object; + + + ACPI_FUNCTION_TRACE ("ut_allocate_object_desc_dbg"); + + + object = acpi_ut_acquire_from_cache (ACPI_MEM_LIST_OPERAND); + if (!object) { + _ACPI_REPORT_ERROR (module_name, line_number, component_id, + ("Could not allocate an object descriptor\n")); + + return_PTR (NULL); + } + + /* Mark the descriptor type */ + + ACPI_SET_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_OPERAND); + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "%p Size %X\n", + object, (u32) sizeof (union acpi_operand_object))); + + return_PTR (object); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_delete_object_desc + * + * PARAMETERS: Object - An Acpi internal object to be deleted + * + * RETURN: None. + * + * DESCRIPTION: Free an ACPI object descriptor or add it to the object cache + * + ******************************************************************************/ + +void +acpi_ut_delete_object_desc ( + union acpi_operand_object *object) +{ + ACPI_FUNCTION_TRACE_PTR ("ut_delete_object_desc", object); + + + /* Object must be an union acpi_operand_object */ + + if (ACPI_GET_DESCRIPTOR_TYPE (object) != ACPI_DESC_TYPE_OPERAND) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "%p is not an ACPI Operand object [%s]\n", object, + acpi_ut_get_descriptor_name (object))); + return_VOID; + } + + acpi_ut_release_to_cache (ACPI_MEM_LIST_OPERAND, object); + + return_VOID; +} + + +#ifdef ACPI_ENABLE_OBJECT_CACHE +/******************************************************************************* + * + * FUNCTION: acpi_ut_delete_object_cache + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Purge the global state object cache. Used during subsystem + * termination. + * + ******************************************************************************/ + +void +acpi_ut_delete_object_cache ( + void) +{ + ACPI_FUNCTION_TRACE ("ut_delete_object_cache"); + + + acpi_ut_delete_generic_cache (ACPI_MEM_LIST_OPERAND); + return_VOID; +} +#endif + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_get_simple_object_size + * + * PARAMETERS: *internal_object - Pointer to the object we are examining + * *obj_length - Where the length is returned + * + * RETURN: Status + * + * DESCRIPTION: This function is called to determine the space required to + * contain a simple object for return to an external user. + * + * The length includes the object structure plus any additional + * needed space. + * + ******************************************************************************/ + +acpi_status +acpi_ut_get_simple_object_size ( + union acpi_operand_object *internal_object, + acpi_size *obj_length) +{ + acpi_size length; + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE_PTR ("ut_get_simple_object_size", internal_object); + + + /* Handle a null object (Could be a uninitialized package element -- which is legal) */ + + if (!internal_object) { + *obj_length = 0; + return_ACPI_STATUS (AE_OK); + } + + /* Start with the length of the Acpi object */ + + length = sizeof (union acpi_object); + + if (ACPI_GET_DESCRIPTOR_TYPE (internal_object) == ACPI_DESC_TYPE_NAMED) { + /* Object is a named object (reference), just return the length */ + + *obj_length = ACPI_ROUND_UP_TO_NATIVE_WORD (length); + return_ACPI_STATUS (status); + } + + /* + * The final length depends on the object type + * Strings and Buffers are packed right up against the parent object and + * must be accessed bytewise or there may be alignment problems on + * certain processors + */ + switch (ACPI_GET_OBJECT_TYPE (internal_object)) { + case ACPI_TYPE_STRING: + + length += (acpi_size) internal_object->string.length + 1; + break; + + + case ACPI_TYPE_BUFFER: + + length += (acpi_size) internal_object->buffer.length; + break; + + + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_POWER: + + /* + * No extra data for these types + */ + break; + + + case ACPI_TYPE_LOCAL_REFERENCE: + + switch (internal_object->reference.opcode) { + case AML_INT_NAMEPATH_OP: + + /* + * Get the actual length of the full pathname to this object. + * The reference will be converted to the pathname to the object + */ + length += ACPI_ROUND_UP_TO_NATIVE_WORD (acpi_ns_get_pathname_length (internal_object->reference.node)); + break; + + default: + + /* + * No other reference opcodes are supported. + * Notably, Locals and Args are not supported, but this may be + * required eventually. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Unsupported Reference opcode=%X in object %p\n", + internal_object->reference.opcode, internal_object)); + status = AE_TYPE; + break; + } + break; + + + default: + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unsupported type=%X in object %p\n", + ACPI_GET_OBJECT_TYPE (internal_object), internal_object)); + status = AE_TYPE; + break; + } + + /* + * Account for the space required by the object rounded up to the next + * multiple of the machine word size. This keeps each object aligned + * on a machine word boundary. (preventing alignment faults on some + * machines.) + */ + *obj_length = ACPI_ROUND_UP_TO_NATIVE_WORD (length); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_get_element_length + * + * PARAMETERS: acpi_pkg_callback + * + * RETURN: Status + * + * DESCRIPTION: Get the length of one package element. + * + ******************************************************************************/ + +acpi_status +acpi_ut_get_element_length ( + u8 object_type, + union acpi_operand_object *source_object, + union acpi_generic_state *state, + void *context) +{ + acpi_status status = AE_OK; + struct acpi_pkg_info *info = (struct acpi_pkg_info *) context; + acpi_size object_space; + + + switch (object_type) { + case ACPI_COPY_TYPE_SIMPLE: + + /* + * Simple object - just get the size (Null object/entry is handled + * here also) and sum it into the running package length + */ + status = acpi_ut_get_simple_object_size (source_object, &object_space); + if (ACPI_FAILURE (status)) { + return (status); + } + + info->length += object_space; + break; + + + case ACPI_COPY_TYPE_PACKAGE: + + /* Package object - nothing much to do here, let the walk handle it */ + + info->num_packages++; + state->pkg.this_target_obj = NULL; + break; + + + default: + + /* No other types allowed */ + + return (AE_BAD_PARAMETER); + } + + return (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_get_package_object_size + * + * PARAMETERS: *internal_object - Pointer to the object we are examining + * *obj_length - Where the length is returned + * + * RETURN: Status + * + * DESCRIPTION: This function is called to determine the space required to + * contain a package object for return to an external user. + * + * This is moderately complex since a package contains other + * objects including packages. + * + ******************************************************************************/ + +acpi_status +acpi_ut_get_package_object_size ( + union acpi_operand_object *internal_object, + acpi_size *obj_length) +{ + acpi_status status; + struct acpi_pkg_info info; + + + ACPI_FUNCTION_TRACE_PTR ("ut_get_package_object_size", internal_object); + + + info.length = 0; + info.object_space = 0; + info.num_packages = 1; + + status = acpi_ut_walk_package_tree (internal_object, NULL, + acpi_ut_get_element_length, &info); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* + * We have handled all of the objects in all levels of the package. + * just add the length of the package objects themselves. + * Round up to the next machine word. + */ + info.length += ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (union acpi_object)) * + (acpi_size) info.num_packages; + + /* Return the total package length */ + + *obj_length = info.length; + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_get_object_size + * + * PARAMETERS: *internal_object - Pointer to the object we are examining + * *obj_length - Where the length will be returned + * + * RETURN: Status + * + * DESCRIPTION: This function is called to determine the space required to + * contain an object for return to an API user. + * + ******************************************************************************/ + +acpi_status +acpi_ut_get_object_size( + union acpi_operand_object *internal_object, + acpi_size *obj_length) +{ + acpi_status status; + + + ACPI_FUNCTION_ENTRY (); + + + if ((ACPI_GET_DESCRIPTOR_TYPE (internal_object) == ACPI_DESC_TYPE_OPERAND) && + (ACPI_GET_OBJECT_TYPE (internal_object) == ACPI_TYPE_PACKAGE)) { + status = acpi_ut_get_package_object_size (internal_object, obj_length); + } + else { + status = acpi_ut_get_simple_object_size (internal_object, obj_length); + } + + return (status); +} + + diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c new file mode 100644 index 000000000000..97a91f3f06f0 --- /dev/null +++ b/drivers/acpi/utilities/utxface.c @@ -0,0 +1,525 @@ +/****************************************************************************** + * + * Module Name: utxface - External interfaces for "global" ACPI functions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include <linux/module.h> + +#include <acpi/acpi.h> +#include <acpi/acevents.h> +#include <acpi/acnamesp.h> +#include <acpi/acparser.h> +#include <acpi/acdispat.h> +#include <acpi/acdebug.h> + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utxface") + + +/******************************************************************************* + * + * FUNCTION: acpi_initialize_subsystem + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Initializes all global variables. This is the first function + * called, so any early initialization belongs here. + * + ******************************************************************************/ + +acpi_status +acpi_initialize_subsystem ( + void) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE ("acpi_initialize_subsystem"); + + + ACPI_DEBUG_EXEC (acpi_ut_init_stack_ptr_trace ()); + + + /* Initialize all globals used by the subsystem */ + + acpi_ut_init_globals (); + + /* Initialize the OS-Dependent layer */ + + status = acpi_os_initialize (); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("OSD failed to initialize, %s\n", + acpi_format_exception (status))); + return_ACPI_STATUS (status); + } + + /* Create the default mutex objects */ + + status = acpi_ut_mutex_initialize (); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Global mutex creation failure, %s\n", + acpi_format_exception (status))); + return_ACPI_STATUS (status); + } + + /* + * Initialize the namespace manager and + * the root of the namespace tree + */ + + status = acpi_ns_root_initialize (); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Namespace initialization failure, %s\n", + acpi_format_exception (status))); + return_ACPI_STATUS (status); + } + + + /* If configured, initialize the AML debugger */ + + ACPI_DEBUGGER_EXEC (status = acpi_db_initialize ()); + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_enable_subsystem + * + * PARAMETERS: Flags - Init/enable Options + * + * RETURN: Status + * + * DESCRIPTION: Completes the subsystem initialization including hardware. + * Puts system into ACPI mode if it isn't already. + * + ******************************************************************************/ + +acpi_status +acpi_enable_subsystem ( + u32 flags) +{ + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE ("acpi_enable_subsystem"); + + + /* + * We must initialize the hardware before we can enable ACPI. + * The values from the FADT are validated here. + */ + if (!(flags & ACPI_NO_HARDWARE_INIT)) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Initializing ACPI hardware\n")); + + status = acpi_hw_initialize (); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + /* Enable ACPI mode */ + + if (!(flags & ACPI_NO_ACPI_ENABLE)) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Going into ACPI mode\n")); + + acpi_gbl_original_mode = acpi_hw_get_mode(); + + status = acpi_enable (); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "acpi_enable failed.\n")); + return_ACPI_STATUS (status); + } + } + + /* + * Install the default op_region handlers. These are installed unless + * other handlers have already been installed via the + * install_address_space_handler interface. + */ + if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Installing default address space handlers\n")); + + status = acpi_ev_install_region_handlers (); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + /* + * Initialize ACPI Event handling (Fixed and General Purpose) + * + * NOTE: We must have the hardware AND events initialized before we can execute + * ANY control methods SAFELY. Any control method can require ACPI hardware + * support, so the hardware MUST be initialized before execution! + */ + if (!(flags & ACPI_NO_EVENT_INIT)) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Initializing ACPI events\n")); + + status = acpi_ev_initialize_events (); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + /* Install the SCI handler and Global Lock handler */ + + if (!(flags & ACPI_NO_HANDLER_INIT)) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Installing SCI/GL handlers\n")); + + status = acpi_ev_install_xrupt_handlers (); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + return_ACPI_STATUS (status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_initialize_objects + * + * PARAMETERS: Flags - Init/enable Options + * + * RETURN: Status + * + * DESCRIPTION: Completes namespace initialization by initializing device + * objects and executing AML code for Regions, buffers, etc. + * + ******************************************************************************/ + +acpi_status +acpi_initialize_objects ( + u32 flags) +{ + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE ("acpi_initialize_objects"); + + + /* + * Run all _REG methods + * + * NOTE: Any objects accessed + * by the _REG methods will be automatically initialized, even if they + * contain executable AML (see call to acpi_ns_initialize_objects below). + */ + if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Executing _REG op_region methods\n")); + + status = acpi_ev_initialize_op_regions (); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + /* + * Initialize the objects that remain uninitialized. This + * runs the executable AML that may be part of the declaration of these + * objects: operation_regions, buffer_fields, Buffers, and Packages. + */ + if (!(flags & ACPI_NO_OBJECT_INIT)) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Completing Initialization of ACPI Objects\n")); + + status = acpi_ns_initialize_objects (); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + /* + * Initialize all device objects in the namespace + * This runs the _STA and _INI methods. + */ + if (!(flags & ACPI_NO_DEVICE_INIT)) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Initializing ACPI Devices\n")); + + status = acpi_ns_initialize_devices (); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + /* + * Empty the caches (delete the cached objects) on the assumption that + * the table load filled them up more than they will be at runtime -- + * thus wasting non-paged memory. + */ + status = acpi_purge_cached_objects (); + + acpi_gbl_startup_flags |= ACPI_INITIALIZED_OK; + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_terminate + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Shutdown the ACPI subsystem. Release all resources. + * + ******************************************************************************/ + +acpi_status +acpi_terminate (void) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("acpi_terminate"); + + + /* Terminate the AML Debugger if present */ + + ACPI_DEBUGGER_EXEC(acpi_gbl_db_terminate_threads = TRUE); + + /* Shutdown and free all resources */ + + acpi_ut_subsystem_shutdown (); + + + /* Free the mutex objects */ + + acpi_ut_mutex_terminate (); + + +#ifdef ACPI_DEBUGGER + + /* Shut down the debugger */ + + acpi_db_terminate (); +#endif + + /* Now we can shutdown the OS-dependent layer */ + + status = acpi_os_terminate (); + return_ACPI_STATUS (status); +} + + +#ifdef ACPI_FUTURE_USAGE + +/***************************************************************************** + * + * FUNCTION: acpi_subsystem_status + * + * PARAMETERS: None + * + * RETURN: Status of the ACPI subsystem + * + * DESCRIPTION: Other drivers that use the ACPI subsystem should call this + * before making any other calls, to ensure the subsystem initial- + * ized successfully. + * + ****************************************************************************/ + +acpi_status +acpi_subsystem_status (void) +{ + if (acpi_gbl_startup_flags & ACPI_INITIALIZED_OK) { + return (AE_OK); + } + else { + return (AE_ERROR); + } +} + + +/****************************************************************************** + * + * FUNCTION: acpi_get_system_info + * + * PARAMETERS: out_buffer - a pointer to a buffer to receive the + * resources for the device + * buffer_length - the number of bytes available in the buffer + * + * RETURN: Status - the status of the call + * + * DESCRIPTION: This function is called to get information about the current + * state of the ACPI subsystem. It will return system information + * in the out_buffer. + * + * If the function fails an appropriate status will be returned + * and the value of out_buffer is undefined. + * + ******************************************************************************/ + +acpi_status +acpi_get_system_info ( + struct acpi_buffer *out_buffer) +{ + struct acpi_system_info *info_ptr; + u32 i; + acpi_status status; + + + ACPI_FUNCTION_TRACE ("acpi_get_system_info"); + + + /* Parameter validation */ + + status = acpi_ut_validate_buffer (out_buffer); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Validate/Allocate/Clear caller buffer */ + + status = acpi_ut_initialize_buffer (out_buffer, sizeof (struct acpi_system_info)); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* + * Populate the return buffer + */ + info_ptr = (struct acpi_system_info *) out_buffer->pointer; + + info_ptr->acpi_ca_version = ACPI_CA_VERSION; + + /* System flags (ACPI capabilities) */ + + info_ptr->flags = ACPI_SYS_MODE_ACPI; + + /* Timer resolution - 24 or 32 bits */ + + if (!acpi_gbl_FADT) { + info_ptr->timer_resolution = 0; + } + else if (acpi_gbl_FADT->tmr_val_ext == 0) { + info_ptr->timer_resolution = 24; + } + else { + info_ptr->timer_resolution = 32; + } + + /* Clear the reserved fields */ + + info_ptr->reserved1 = 0; + info_ptr->reserved2 = 0; + + /* Current debug levels */ + + info_ptr->debug_layer = acpi_dbg_layer; + info_ptr->debug_level = acpi_dbg_level; + + /* Current status of the ACPI tables, per table type */ + + info_ptr->num_table_types = NUM_ACPI_TABLE_TYPES; + for (i = 0; i < NUM_ACPI_TABLE_TYPES; i++) { + info_ptr->table_info[i].count = acpi_gbl_table_lists[i].count; + } + + return_ACPI_STATUS (AE_OK); +} +EXPORT_SYMBOL(acpi_get_system_info); + + +/***************************************************************************** + * + * FUNCTION: acpi_install_initialization_handler + * + * PARAMETERS: Handler - Callback procedure + * + * RETURN: Status + * + * DESCRIPTION: Install an initialization handler + * + * TBD: When a second function is added, must save the Function also. + * + ****************************************************************************/ + +acpi_status +acpi_install_initialization_handler ( + acpi_init_handler handler, + u32 function) +{ + + if (!handler) { + return (AE_BAD_PARAMETER); + } + + if (acpi_gbl_init_handler) { + return (AE_ALREADY_EXISTS); + } + + acpi_gbl_init_handler = handler; + return AE_OK; +} + +#endif /* ACPI_FUTURE_USAGE */ + + +/***************************************************************************** + * + * FUNCTION: acpi_purge_cached_objects + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Empty all caches (delete the cached objects) + * + ****************************************************************************/ + +acpi_status +acpi_purge_cached_objects (void) +{ + ACPI_FUNCTION_TRACE ("acpi_purge_cached_objects"); + + +#ifdef ACPI_ENABLE_OBJECT_CACHE + acpi_ut_delete_generic_state_cache (); + acpi_ut_delete_object_cache (); + acpi_ds_delete_walk_state_cache (); + acpi_ps_delete_parse_cache (); +#endif + + return_ACPI_STATUS (AE_OK); +} |