Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.18-rc2 417 lines 12 kB view raw
1/****************************************************************************** 2 * 3 * Module Name: nsload - namespace loading/expanding/contracting procedures 4 * 5 *****************************************************************************/ 6 7/* 8 * Copyright (C) 2000 - 2006, R. Byron Moore 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 */ 43 44#include <acpi/acpi.h> 45#include <acpi/acnamesp.h> 46#include <acpi/acdispat.h> 47 48#define _COMPONENT ACPI_NAMESPACE 49ACPI_MODULE_NAME("nsload") 50 51/* Local prototypes */ 52static acpi_status acpi_ns_load_table_by_type(acpi_table_type table_type); 53 54#ifdef ACPI_FUTURE_IMPLEMENTATION 55acpi_status acpi_ns_unload_namespace(acpi_handle handle); 56 57static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle); 58#endif 59 60#ifndef ACPI_NO_METHOD_EXECUTION 61/******************************************************************************* 62 * 63 * FUNCTION: acpi_ns_load_table 64 * 65 * PARAMETERS: table_desc - Descriptor for table to be loaded 66 * Node - Owning NS node 67 * 68 * RETURN: Status 69 * 70 * DESCRIPTION: Load one ACPI table into the namespace 71 * 72 ******************************************************************************/ 73 74acpi_status 75acpi_ns_load_table(struct acpi_table_desc *table_desc, 76 struct acpi_namespace_node *node) 77{ 78 acpi_status status; 79 80 ACPI_FUNCTION_TRACE(ns_load_table); 81 82 /* Check if table contains valid AML (must be DSDT, PSDT, SSDT, etc.) */ 83 84 if (! 85 (acpi_gbl_table_data[table_desc->type]. 86 flags & ACPI_TABLE_EXECUTABLE)) { 87 88 /* Just ignore this table */ 89 90 return_ACPI_STATUS(AE_OK); 91 } 92 93 /* Check validity of the AML start and length */ 94 95 if (!table_desc->aml_start) { 96 ACPI_ERROR((AE_INFO, "Null AML pointer")); 97 return_ACPI_STATUS(AE_BAD_PARAMETER); 98 } 99 100 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "AML block at %p\n", 101 table_desc->aml_start)); 102 103 /* Ignore table if there is no AML contained within */ 104 105 if (!table_desc->aml_length) { 106 ACPI_WARNING((AE_INFO, "Zero-length AML block in table [%4.4s]", 107 table_desc->pointer->signature)); 108 return_ACPI_STATUS(AE_OK); 109 } 110 111 /* 112 * Parse the table and load the namespace with all named 113 * objects found within. Control methods are NOT parsed 114 * at this time. In fact, the control methods cannot be 115 * parsed until the entire namespace is loaded, because 116 * if a control method makes a forward reference (call) 117 * to another control method, we can't continue parsing 118 * because we don't know how many arguments to parse next! 119 */ 120 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 121 "**** Loading table into namespace ****\n")); 122 123 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 124 if (ACPI_FAILURE(status)) { 125 return_ACPI_STATUS(status); 126 } 127 128 status = acpi_ns_parse_table(table_desc, node->child); 129 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 130 131 if (ACPI_FAILURE(status)) { 132 return_ACPI_STATUS(status); 133 } 134 135 /* 136 * Now we can parse the control methods. We always parse 137 * them here for a sanity check, and if configured for 138 * just-in-time parsing, we delete the control method 139 * parse trees. 140 */ 141 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 142 "**** Begin Table Method Parsing and Object Initialization ****\n")); 143 144 status = acpi_ds_initialize_objects(table_desc, node); 145 146 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 147 "**** Completed Table Method Parsing and Object Initialization ****\n")); 148 149 return_ACPI_STATUS(status); 150} 151 152/******************************************************************************* 153 * 154 * FUNCTION: acpi_ns_load_table_by_type 155 * 156 * PARAMETERS: table_type - Id of the table type to load 157 * 158 * RETURN: Status 159 * 160 * DESCRIPTION: Load an ACPI table or tables into the namespace. All tables 161 * of the given type are loaded. The mechanism allows this 162 * routine to be called repeatedly. 163 * 164 ******************************************************************************/ 165 166static acpi_status acpi_ns_load_table_by_type(acpi_table_type table_type) 167{ 168 u32 i; 169 acpi_status status; 170 struct acpi_table_desc *table_desc; 171 172 ACPI_FUNCTION_TRACE(ns_load_table_by_type); 173 174 status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES); 175 if (ACPI_FAILURE(status)) { 176 return_ACPI_STATUS(status); 177 } 178 179 /* 180 * Table types supported are: 181 * DSDT (one), SSDT/PSDT (multiple) 182 */ 183 switch (table_type) { 184 case ACPI_TABLE_ID_DSDT: 185 186 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Namespace load: DSDT\n")); 187 188 table_desc = acpi_gbl_table_lists[ACPI_TABLE_ID_DSDT].next; 189 190 /* If table already loaded into namespace, just return */ 191 192 if (table_desc->loaded_into_namespace) { 193 goto unlock_and_exit; 194 } 195 196 /* Now load the single DSDT */ 197 198 status = acpi_ns_load_table(table_desc, acpi_gbl_root_node); 199 if (ACPI_SUCCESS(status)) { 200 table_desc->loaded_into_namespace = TRUE; 201 } 202 break; 203 204 case ACPI_TABLE_ID_SSDT: 205 case ACPI_TABLE_ID_PSDT: 206 207 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 208 "Namespace load: %d SSDT or PSDTs\n", 209 acpi_gbl_table_lists[table_type].count)); 210 211 /* 212 * Traverse list of SSDT or PSDT tables 213 */ 214 table_desc = acpi_gbl_table_lists[table_type].next; 215 for (i = 0; i < acpi_gbl_table_lists[table_type].count; i++) { 216 /* 217 * Only attempt to load table into namespace if it is not 218 * already loaded! 219 */ 220 if (!table_desc->loaded_into_namespace) { 221 status = 222 acpi_ns_load_table(table_desc, 223 acpi_gbl_root_node); 224 if (ACPI_FAILURE(status)) { 225 break; 226 } 227 228 table_desc->loaded_into_namespace = TRUE; 229 } 230 231 table_desc = table_desc->next; 232 } 233 break; 234 235 default: 236 status = AE_SUPPORT; 237 break; 238 } 239 240 unlock_and_exit: 241 (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); 242 return_ACPI_STATUS(status); 243} 244 245/******************************************************************************* 246 * 247 * FUNCTION: acpi_load_namespace 248 * 249 * PARAMETERS: None 250 * 251 * RETURN: Status 252 * 253 * DESCRIPTION: Load the name space from what ever is pointed to by DSDT. 254 * (DSDT points to either the BIOS or a buffer.) 255 * 256 ******************************************************************************/ 257 258acpi_status acpi_ns_load_namespace(void) 259{ 260 acpi_status status; 261 262 ACPI_FUNCTION_TRACE(acpi_load_name_space); 263 264 /* There must be at least a DSDT installed */ 265 266 if (acpi_gbl_DSDT == NULL) { 267 ACPI_ERROR((AE_INFO, "DSDT is not in memory")); 268 return_ACPI_STATUS(AE_NO_ACPI_TABLES); 269 } 270 271 /* 272 * Load the namespace. The DSDT is required, 273 * but the SSDT and PSDT tables are optional. 274 */ 275 status = acpi_ns_load_table_by_type(ACPI_TABLE_ID_DSDT); 276 if (ACPI_FAILURE(status)) { 277 return_ACPI_STATUS(status); 278 } 279 280 /* Ignore exceptions from these */ 281 282 (void)acpi_ns_load_table_by_type(ACPI_TABLE_ID_SSDT); 283 (void)acpi_ns_load_table_by_type(ACPI_TABLE_ID_PSDT); 284 285 ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, 286 "ACPI Namespace successfully loaded at root %p\n", 287 acpi_gbl_root_node)); 288 289 return_ACPI_STATUS(status); 290} 291 292#ifdef ACPI_FUTURE_IMPLEMENTATION 293/******************************************************************************* 294 * 295 * FUNCTION: acpi_ns_delete_subtree 296 * 297 * PARAMETERS: start_handle - Handle in namespace where search begins 298 * 299 * RETURNS Status 300 * 301 * DESCRIPTION: Walks the namespace starting at the given handle and deletes 302 * all objects, entries, and scopes in the entire subtree. 303 * 304 * Namespace/Interpreter should be locked or the subsystem should 305 * be in shutdown before this routine is called. 306 * 307 ******************************************************************************/ 308 309static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle) 310{ 311 acpi_status status; 312 acpi_handle child_handle; 313 acpi_handle parent_handle; 314 acpi_handle next_child_handle; 315 acpi_handle dummy; 316 u32 level; 317 318 ACPI_FUNCTION_TRACE(ns_delete_subtree); 319 320 parent_handle = start_handle; 321 child_handle = NULL; 322 level = 1; 323 324 /* 325 * Traverse the tree of objects until we bubble back up 326 * to where we started. 327 */ 328 while (level > 0) { 329 330 /* Attempt to get the next object in this scope */ 331 332 status = acpi_get_next_object(ACPI_TYPE_ANY, parent_handle, 333 child_handle, &next_child_handle); 334 335 child_handle = next_child_handle; 336 337 /* Did we get a new object? */ 338 339 if (ACPI_SUCCESS(status)) { 340 341 /* Check if this object has any children */ 342 343 if (ACPI_SUCCESS 344 (acpi_get_next_object 345 (ACPI_TYPE_ANY, child_handle, NULL, &dummy))) { 346 /* 347 * There is at least one child of this object, 348 * visit the object 349 */ 350 level++; 351 parent_handle = child_handle; 352 child_handle = NULL; 353 } 354 } else { 355 /* 356 * No more children in this object, go back up to 357 * the object's parent 358 */ 359 level--; 360 361 /* Delete all children now */ 362 363 acpi_ns_delete_children(child_handle); 364 365 child_handle = parent_handle; 366 status = acpi_get_parent(parent_handle, &parent_handle); 367 if (ACPI_FAILURE(status)) { 368 return_ACPI_STATUS(status); 369 } 370 } 371 } 372 373 /* Now delete the starting object, and we are done */ 374 375 acpi_ns_delete_node(child_handle); 376 377 return_ACPI_STATUS(AE_OK); 378} 379 380/******************************************************************************* 381 * 382 * FUNCTION: acpi_ns_unload_name_space 383 * 384 * PARAMETERS: Handle - Root of namespace subtree to be deleted 385 * 386 * RETURN: Status 387 * 388 * DESCRIPTION: Shrinks the namespace, typically in response to an undocking 389 * event. Deletes an entire subtree starting from (and 390 * including) the given handle. 391 * 392 ******************************************************************************/ 393 394acpi_status acpi_ns_unload_namespace(acpi_handle handle) 395{ 396 acpi_status status; 397 398 ACPI_FUNCTION_TRACE(ns_unload_name_space); 399 400 /* Parameter validation */ 401 402 if (!acpi_gbl_root_node) { 403 return_ACPI_STATUS(AE_NO_NAMESPACE); 404 } 405 406 if (!handle) { 407 return_ACPI_STATUS(AE_BAD_PARAMETER); 408 } 409 410 /* This function does the real work */ 411 412 status = acpi_ns_delete_subtree(handle); 413 414 return_ACPI_STATUS(status); 415} 416#endif 417#endif