Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.15-rc3 501 lines 14 kB view raw
1/****************************************************************************** 2 * 3 * Module Name: exconfig - Namespace reconfiguration (Load/Unload opcodes) 4 * 5 *****************************************************************************/ 6 7/* 8 * Copyright (C) 2000 - 2005, 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/acinterp.h> 46#include <acpi/amlcode.h> 47#include <acpi/acnamesp.h> 48#include <acpi/acevents.h> 49#include <acpi/actables.h> 50#include <acpi/acdispat.h> 51 52#define _COMPONENT ACPI_EXECUTER 53ACPI_MODULE_NAME("exconfig") 54 55/* Local prototypes */ 56static acpi_status 57acpi_ex_add_table(struct acpi_table_header *table, 58 struct acpi_namespace_node *parent_node, 59 union acpi_operand_object **ddb_handle); 60 61/******************************************************************************* 62 * 63 * FUNCTION: acpi_ex_add_table 64 * 65 * PARAMETERS: Table - Pointer to raw table 66 * parent_node - Where to load the table (scope) 67 * ddb_handle - Where to return the table handle. 68 * 69 * RETURN: Status 70 * 71 * DESCRIPTION: Common function to Install and Load an ACPI table with a 72 * returned table handle. 73 * 74 ******************************************************************************/ 75 76static acpi_status 77acpi_ex_add_table(struct acpi_table_header *table, 78 struct acpi_namespace_node *parent_node, 79 union acpi_operand_object **ddb_handle) 80{ 81 acpi_status status; 82 struct acpi_table_desc table_info; 83 union acpi_operand_object *obj_desc; 84 85 ACPI_FUNCTION_TRACE("ex_add_table"); 86 87 /* Create an object to be the table handle */ 88 89 obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_REFERENCE); 90 if (!obj_desc) { 91 return_ACPI_STATUS(AE_NO_MEMORY); 92 } 93 94 /* Init the table handle */ 95 96 obj_desc->reference.opcode = AML_LOAD_OP; 97 *ddb_handle = obj_desc; 98 99 /* Install the new table into the local data structures */ 100 101 ACPI_MEMSET(&table_info, 0, sizeof(struct acpi_table_desc)); 102 103 table_info.type = ACPI_TABLE_SSDT; 104 table_info.pointer = table; 105 table_info.length = (acpi_size) table->length; 106 table_info.allocation = ACPI_MEM_ALLOCATED; 107 108 status = acpi_tb_install_table(&table_info); 109 obj_desc->reference.object = table_info.installed_desc; 110 111 if (ACPI_FAILURE(status)) { 112 if (status == AE_ALREADY_EXISTS) { 113 /* Table already exists, just return the handle */ 114 115 return_ACPI_STATUS(AE_OK); 116 } 117 goto cleanup; 118 } 119 120 /* Add the table to the namespace */ 121 122 status = acpi_ns_load_table(table_info.installed_desc, parent_node); 123 if (ACPI_FAILURE(status)) { 124 /* Uninstall table on error */ 125 126 (void)acpi_tb_uninstall_table(table_info.installed_desc); 127 goto cleanup; 128 } 129 130 return_ACPI_STATUS(AE_OK); 131 132 cleanup: 133 acpi_ut_remove_reference(obj_desc); 134 *ddb_handle = NULL; 135 return_ACPI_STATUS(status); 136} 137 138/******************************************************************************* 139 * 140 * FUNCTION: acpi_ex_load_table_op 141 * 142 * PARAMETERS: walk_state - Current state with operands 143 * return_desc - Where to store the return object 144 * 145 * RETURN: Status 146 * 147 * DESCRIPTION: Load an ACPI table 148 * 149 ******************************************************************************/ 150 151acpi_status 152acpi_ex_load_table_op(struct acpi_walk_state *walk_state, 153 union acpi_operand_object **return_desc) 154{ 155 acpi_status status; 156 union acpi_operand_object **operand = &walk_state->operands[0]; 157 struct acpi_table_header *table; 158 struct acpi_namespace_node *parent_node; 159 struct acpi_namespace_node *start_node; 160 struct acpi_namespace_node *parameter_node = NULL; 161 union acpi_operand_object *ddb_handle; 162 163 ACPI_FUNCTION_TRACE("ex_load_table_op"); 164 165#if 0 166 /* 167 * Make sure that the signature does not match one of the tables that 168 * is already loaded. 169 */ 170 status = acpi_tb_match_signature(operand[0]->string.pointer, NULL); 171 if (status == AE_OK) { 172 /* Signature matched -- don't allow override */ 173 174 return_ACPI_STATUS(AE_ALREADY_EXISTS); 175 } 176#endif 177 178 /* Find the ACPI table */ 179 180 status = acpi_tb_find_table(operand[0]->string.pointer, 181 operand[1]->string.pointer, 182 operand[2]->string.pointer, &table); 183 if (ACPI_FAILURE(status)) { 184 if (status != AE_NOT_FOUND) { 185 return_ACPI_STATUS(status); 186 } 187 188 /* Table not found, return an Integer=0 and AE_OK */ 189 190 ddb_handle = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); 191 if (!ddb_handle) { 192 return_ACPI_STATUS(AE_NO_MEMORY); 193 } 194 195 ddb_handle->integer.value = 0; 196 *return_desc = ddb_handle; 197 198 return_ACPI_STATUS(AE_OK); 199 } 200 201 /* Default nodes */ 202 203 start_node = walk_state->scope_info->scope.node; 204 parent_node = acpi_gbl_root_node; 205 206 /* root_path (optional parameter) */ 207 208 if (operand[3]->string.length > 0) { 209 /* 210 * Find the node referenced by the root_path_string. This is the 211 * location within the namespace where the table will be loaded. 212 */ 213 status = 214 acpi_ns_get_node_by_path(operand[3]->string.pointer, 215 start_node, ACPI_NS_SEARCH_PARENT, 216 &parent_node); 217 if (ACPI_FAILURE(status)) { 218 return_ACPI_STATUS(status); 219 } 220 } 221 222 /* parameter_path (optional parameter) */ 223 224 if (operand[4]->string.length > 0) { 225 if ((operand[4]->string.pointer[0] != '\\') && 226 (operand[4]->string.pointer[0] != '^')) { 227 /* 228 * Path is not absolute, so it will be relative to the node 229 * referenced by the root_path_string (or the NS root if omitted) 230 */ 231 start_node = parent_node; 232 } 233 234 /* Find the node referenced by the parameter_path_string */ 235 236 status = 237 acpi_ns_get_node_by_path(operand[4]->string.pointer, 238 start_node, ACPI_NS_SEARCH_PARENT, 239 &parameter_node); 240 if (ACPI_FAILURE(status)) { 241 return_ACPI_STATUS(status); 242 } 243 } 244 245 /* Load the table into the namespace */ 246 247 status = acpi_ex_add_table(table, parent_node, &ddb_handle); 248 if (ACPI_FAILURE(status)) { 249 return_ACPI_STATUS(status); 250 } 251 252 /* Parameter Data (optional) */ 253 254 if (parameter_node) { 255 /* Store the parameter data into the optional parameter object */ 256 257 status = acpi_ex_store(operand[5], 258 ACPI_CAST_PTR(union acpi_operand_object, 259 parameter_node), 260 walk_state); 261 if (ACPI_FAILURE(status)) { 262 (void)acpi_ex_unload_table(ddb_handle); 263 return_ACPI_STATUS(status); 264 } 265 } 266 267 *return_desc = ddb_handle; 268 return_ACPI_STATUS(status); 269} 270 271/******************************************************************************* 272 * 273 * FUNCTION: acpi_ex_load_op 274 * 275 * PARAMETERS: obj_desc - Region or Field where the table will be 276 * obtained 277 * Target - Where a handle to the table will be stored 278 * walk_state - Current state 279 * 280 * RETURN: Status 281 * 282 * DESCRIPTION: Load an ACPI table from a field or operation region 283 * 284 ******************************************************************************/ 285 286acpi_status 287acpi_ex_load_op(union acpi_operand_object *obj_desc, 288 union acpi_operand_object *target, 289 struct acpi_walk_state *walk_state) 290{ 291 acpi_status status; 292 union acpi_operand_object *ddb_handle; 293 union acpi_operand_object *buffer_desc = NULL; 294 struct acpi_table_header *table_ptr = NULL; 295 acpi_physical_address address; 296 struct acpi_table_header table_header; 297 u32 i; 298 299 ACPI_FUNCTION_TRACE("ex_load_op"); 300 301 /* Object can be either an op_region or a Field */ 302 303 switch (ACPI_GET_OBJECT_TYPE(obj_desc)) { 304 case ACPI_TYPE_REGION: 305 306 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Region %p %s\n", 307 obj_desc, 308 acpi_ut_get_object_type_name(obj_desc))); 309 310 /* 311 * If the Region Address and Length have not been previously evaluated, 312 * evaluate them now and save the results. 313 */ 314 if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { 315 status = acpi_ds_get_region_arguments(obj_desc); 316 if (ACPI_FAILURE(status)) { 317 return_ACPI_STATUS(status); 318 } 319 } 320 321 /* Get the base physical address of the region */ 322 323 address = obj_desc->region.address; 324 325 /* Get the table length from the table header */ 326 327 table_header.length = 0; 328 for (i = 0; i < 8; i++) { 329 status = 330 acpi_ev_address_space_dispatch(obj_desc, ACPI_READ, 331 (acpi_physical_address) 332 (i + address), 8, 333 ((u8 *) & 334 table_header) + i); 335 if (ACPI_FAILURE(status)) { 336 return_ACPI_STATUS(status); 337 } 338 } 339 340 /* Sanity check the table length */ 341 342 if (table_header.length < sizeof(struct acpi_table_header)) { 343 return_ACPI_STATUS(AE_BAD_HEADER); 344 } 345 346 /* Allocate a buffer for the entire table */ 347 348 table_ptr = ACPI_MEM_ALLOCATE(table_header.length); 349 if (!table_ptr) { 350 return_ACPI_STATUS(AE_NO_MEMORY); 351 } 352 353 /* Get the entire table from the op region */ 354 355 for (i = 0; i < table_header.length; i++) { 356 status = 357 acpi_ev_address_space_dispatch(obj_desc, ACPI_READ, 358 (acpi_physical_address) 359 (i + address), 8, 360 ((u8 *) table_ptr + 361 i)); 362 if (ACPI_FAILURE(status)) { 363 goto cleanup; 364 } 365 } 366 break; 367 368 case ACPI_TYPE_LOCAL_REGION_FIELD: 369 case ACPI_TYPE_LOCAL_BANK_FIELD: 370 case ACPI_TYPE_LOCAL_INDEX_FIELD: 371 372 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Field %p %s\n", 373 obj_desc, 374 acpi_ut_get_object_type_name(obj_desc))); 375 376 /* 377 * The length of the field must be at least as large as the table. 378 * Read the entire field and thus the entire table. Buffer is 379 * allocated during the read. 380 */ 381 status = 382 acpi_ex_read_data_from_field(walk_state, obj_desc, 383 &buffer_desc); 384 if (ACPI_FAILURE(status)) { 385 return_ACPI_STATUS(status); 386 } 387 388 table_ptr = ACPI_CAST_PTR(struct acpi_table_header, 389 buffer_desc->buffer.pointer); 390 391 /* All done with the buffer_desc, delete it */ 392 393 buffer_desc->buffer.pointer = NULL; 394 acpi_ut_remove_reference(buffer_desc); 395 396 /* Sanity check the table length */ 397 398 if (table_ptr->length < sizeof(struct acpi_table_header)) { 399 status = AE_BAD_HEADER; 400 goto cleanup; 401 } 402 break; 403 404 default: 405 return_ACPI_STATUS(AE_AML_OPERAND_TYPE); 406 } 407 408 /* The table must be either an SSDT or a PSDT */ 409 410 if ((!ACPI_STRNCMP(table_ptr->signature, 411 acpi_gbl_table_data[ACPI_TABLE_PSDT].signature, 412 acpi_gbl_table_data[ACPI_TABLE_PSDT].sig_length)) && 413 (!ACPI_STRNCMP(table_ptr->signature, 414 acpi_gbl_table_data[ACPI_TABLE_SSDT].signature, 415 acpi_gbl_table_data[ACPI_TABLE_SSDT].sig_length))) { 416 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 417 "Table has invalid signature [%4.4s], must be SSDT or PSDT\n", 418 table_ptr->signature)); 419 status = AE_BAD_SIGNATURE; 420 goto cleanup; 421 } 422 423 /* Install the new table into the local data structures */ 424 425 status = acpi_ex_add_table(table_ptr, acpi_gbl_root_node, &ddb_handle); 426 if (ACPI_FAILURE(status)) { 427 /* On error, table_ptr was deallocated above */ 428 429 return_ACPI_STATUS(status); 430 } 431 432 /* Store the ddb_handle into the Target operand */ 433 434 status = acpi_ex_store(ddb_handle, target, walk_state); 435 if (ACPI_FAILURE(status)) { 436 (void)acpi_ex_unload_table(ddb_handle); 437 438 /* table_ptr was deallocated above */ 439 440 return_ACPI_STATUS(status); 441 } 442 443 cleanup: 444 if (ACPI_FAILURE(status)) { 445 ACPI_MEM_FREE(table_ptr); 446 } 447 return_ACPI_STATUS(status); 448} 449 450/******************************************************************************* 451 * 452 * FUNCTION: acpi_ex_unload_table 453 * 454 * PARAMETERS: ddb_handle - Handle to a previously loaded table 455 * 456 * RETURN: Status 457 * 458 * DESCRIPTION: Unload an ACPI table 459 * 460 ******************************************************************************/ 461 462acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) 463{ 464 acpi_status status = AE_OK; 465 union acpi_operand_object *table_desc = ddb_handle; 466 struct acpi_table_desc *table_info; 467 468 ACPI_FUNCTION_TRACE("ex_unload_table"); 469 470 /* 471 * Validate the handle 472 * Although the handle is partially validated in acpi_ex_reconfiguration(), 473 * when it calls acpi_ex_resolve_operands(), the handle is more completely 474 * validated here. 475 */ 476 if ((!ddb_handle) || 477 (ACPI_GET_DESCRIPTOR_TYPE(ddb_handle) != ACPI_DESC_TYPE_OPERAND) || 478 (ACPI_GET_OBJECT_TYPE(ddb_handle) != ACPI_TYPE_LOCAL_REFERENCE)) { 479 return_ACPI_STATUS(AE_BAD_PARAMETER); 480 } 481 482 /* Get the actual table descriptor from the ddb_handle */ 483 484 table_info = (struct acpi_table_desc *)table_desc->reference.object; 485 486 /* 487 * Delete the entire namespace under this table Node 488 * (Offset contains the table_id) 489 */ 490 acpi_ns_delete_namespace_by_owner(table_info->owner_id); 491 acpi_ut_release_owner_id(&table_info->owner_id); 492 493 /* Delete the table itself */ 494 495 (void)acpi_tb_uninstall_table(table_info->installed_desc); 496 497 /* Delete the table descriptor (ddb_handle) */ 498 499 acpi_ut_remove_reference(table_desc); 500 return_ACPI_STATUS(status); 501}