Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.13 644 lines 18 kB view raw
1/****************************************************************************** 2 * 3 * Module Name: excreate - Named object creation 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 45#include <acpi/acpi.h> 46#include <acpi/acinterp.h> 47#include <acpi/amlcode.h> 48#include <acpi/acnamesp.h> 49#include <acpi/acevents.h> 50#include <acpi/actables.h> 51 52 53#define _COMPONENT ACPI_EXECUTER 54 ACPI_MODULE_NAME ("excreate") 55 56 57#ifndef ACPI_NO_METHOD_EXECUTION 58/******************************************************************************* 59 * 60 * FUNCTION: acpi_ex_create_alias 61 * 62 * PARAMETERS: walk_state - Current state, contains operands 63 * 64 * RETURN: Status 65 * 66 * DESCRIPTION: Create a new named alias 67 * 68 ******************************************************************************/ 69 70acpi_status 71acpi_ex_create_alias ( 72 struct acpi_walk_state *walk_state) 73{ 74 struct acpi_namespace_node *target_node; 75 struct acpi_namespace_node *alias_node; 76 acpi_status status = AE_OK; 77 78 79 ACPI_FUNCTION_TRACE ("ex_create_alias"); 80 81 82 /* Get the source/alias operands (both namespace nodes) */ 83 84 alias_node = (struct acpi_namespace_node *) walk_state->operands[0]; 85 target_node = (struct acpi_namespace_node *) walk_state->operands[1]; 86 87 if ((target_node->type == ACPI_TYPE_LOCAL_ALIAS) || 88 (target_node->type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) { 89 /* 90 * Dereference an existing alias so that we don't create a chain 91 * of aliases. With this code, we guarantee that an alias is 92 * always exactly one level of indirection away from the 93 * actual aliased name. 94 */ 95 target_node = ACPI_CAST_PTR (struct acpi_namespace_node, target_node->object); 96 } 97 98 /* 99 * For objects that can never change (i.e., the NS node will 100 * permanently point to the same object), we can simply attach 101 * the object to the new NS node. For other objects (such as 102 * Integers, buffers, etc.), we have to point the Alias node 103 * to the original Node. 104 */ 105 switch (target_node->type) { 106 case ACPI_TYPE_INTEGER: 107 case ACPI_TYPE_STRING: 108 case ACPI_TYPE_BUFFER: 109 case ACPI_TYPE_PACKAGE: 110 case ACPI_TYPE_BUFFER_FIELD: 111 112 /* 113 * The new alias has the type ALIAS and points to the original 114 * NS node, not the object itself. This is because for these 115 * types, the object can change dynamically via a Store. 116 */ 117 alias_node->type = ACPI_TYPE_LOCAL_ALIAS; 118 alias_node->object = ACPI_CAST_PTR (union acpi_operand_object, target_node); 119 break; 120 121 case ACPI_TYPE_METHOD: 122 123 /* 124 * The new alias has the type ALIAS and points to the original 125 * NS node, not the object itself. This is because for these 126 * types, the object can change dynamically via a Store. 127 */ 128 alias_node->type = ACPI_TYPE_LOCAL_METHOD_ALIAS; 129 alias_node->object = ACPI_CAST_PTR (union acpi_operand_object, target_node); 130 break; 131 132 default: 133 134 /* Attach the original source object to the new Alias Node */ 135 136 /* 137 * The new alias assumes the type of the target, and it points 138 * to the same object. The reference count of the object has an 139 * additional reference to prevent deletion out from under either the 140 * target node or the alias Node 141 */ 142 status = acpi_ns_attach_object (alias_node, 143 acpi_ns_get_attached_object (target_node), target_node->type); 144 break; 145 } 146 147 /* Since both operands are Nodes, we don't need to delete them */ 148 149 return_ACPI_STATUS (status); 150} 151 152 153/******************************************************************************* 154 * 155 * FUNCTION: acpi_ex_create_event 156 * 157 * PARAMETERS: walk_state - Current state 158 * 159 * RETURN: Status 160 * 161 * DESCRIPTION: Create a new event object 162 * 163 ******************************************************************************/ 164 165acpi_status 166acpi_ex_create_event ( 167 struct acpi_walk_state *walk_state) 168{ 169 acpi_status status; 170 union acpi_operand_object *obj_desc; 171 172 173 ACPI_FUNCTION_TRACE ("ex_create_event"); 174 175 176 obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_EVENT); 177 if (!obj_desc) { 178 status = AE_NO_MEMORY; 179 goto cleanup; 180 } 181 182 /* 183 * Create the actual OS semaphore, with zero initial units -- meaning 184 * that the event is created in an unsignalled state 185 */ 186 status = acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT, 0, 187 &obj_desc->event.semaphore); 188 if (ACPI_FAILURE (status)) { 189 goto cleanup; 190 } 191 192 /* Attach object to the Node */ 193 194 status = acpi_ns_attach_object ((struct acpi_namespace_node *) walk_state->operands[0], 195 obj_desc, ACPI_TYPE_EVENT); 196 197cleanup: 198 /* 199 * Remove local reference to the object (on error, will cause deletion 200 * of both object and semaphore if present.) 201 */ 202 acpi_ut_remove_reference (obj_desc); 203 return_ACPI_STATUS (status); 204} 205 206 207/******************************************************************************* 208 * 209 * FUNCTION: acpi_ex_create_mutex 210 * 211 * PARAMETERS: walk_state - Current state 212 * 213 * RETURN: Status 214 * 215 * DESCRIPTION: Create a new mutex object 216 * 217 * Mutex (Name[0], sync_level[1]) 218 * 219 ******************************************************************************/ 220 221acpi_status 222acpi_ex_create_mutex ( 223 struct acpi_walk_state *walk_state) 224{ 225 acpi_status status = AE_OK; 226 union acpi_operand_object *obj_desc; 227 228 229 ACPI_FUNCTION_TRACE_PTR ("ex_create_mutex", ACPI_WALK_OPERANDS); 230 231 232 /* Create the new mutex object */ 233 234 obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_MUTEX); 235 if (!obj_desc) { 236 status = AE_NO_MEMORY; 237 goto cleanup; 238 } 239 240 /* 241 * Create the actual OS semaphore. 242 * One unit max to make it a mutex, with one initial unit to allow 243 * the mutex to be acquired. 244 */ 245 status = acpi_os_create_semaphore (1, 1, &obj_desc->mutex.semaphore); 246 if (ACPI_FAILURE (status)) { 247 goto cleanup; 248 } 249 250 /* Init object and attach to NS node */ 251 252 obj_desc->mutex.sync_level = (u8) walk_state->operands[1]->integer.value; 253 obj_desc->mutex.node = (struct acpi_namespace_node *) walk_state->operands[0]; 254 255 status = acpi_ns_attach_object (obj_desc->mutex.node, 256 obj_desc, ACPI_TYPE_MUTEX); 257 258 259cleanup: 260 /* 261 * Remove local reference to the object (on error, will cause deletion 262 * of both object and semaphore if present.) 263 */ 264 acpi_ut_remove_reference (obj_desc); 265 return_ACPI_STATUS (status); 266} 267 268 269/******************************************************************************* 270 * 271 * FUNCTION: acpi_ex_create_region 272 * 273 * PARAMETERS: aml_start - Pointer to the region declaration AML 274 * aml_length - Max length of the declaration AML 275 * region_space - space_iD for the region 276 * walk_state - Current state 277 * 278 * RETURN: Status 279 * 280 * DESCRIPTION: Create a new operation region object 281 * 282 ******************************************************************************/ 283 284acpi_status 285acpi_ex_create_region ( 286 u8 *aml_start, 287 u32 aml_length, 288 u8 region_space, 289 struct acpi_walk_state *walk_state) 290{ 291 acpi_status status; 292 union acpi_operand_object *obj_desc; 293 struct acpi_namespace_node *node; 294 union acpi_operand_object *region_obj2; 295 296 297 ACPI_FUNCTION_TRACE ("ex_create_region"); 298 299 300 /* Get the Namespace Node */ 301 302 node = walk_state->op->common.node; 303 304 /* 305 * If the region object is already attached to this node, 306 * just return 307 */ 308 if (acpi_ns_get_attached_object (node)) { 309 return_ACPI_STATUS (AE_OK); 310 } 311 312 /* 313 * Space ID must be one of the predefined IDs, or in the user-defined 314 * range 315 */ 316 if ((region_space >= ACPI_NUM_PREDEFINED_REGIONS) && 317 (region_space < ACPI_USER_REGION_BEGIN)) { 318 ACPI_REPORT_ERROR (("Invalid address_space type %X\n", region_space)); 319 return_ACPI_STATUS (AE_AML_INVALID_SPACE_ID); 320 } 321 322 ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Region Type - %s (%X)\n", 323 acpi_ut_get_region_name (region_space), region_space)); 324 325 /* Create the region descriptor */ 326 327 obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_REGION); 328 if (!obj_desc) { 329 status = AE_NO_MEMORY; 330 goto cleanup; 331 } 332 333 /* 334 * Remember location in AML stream of address & length 335 * operands since they need to be evaluated at run time. 336 */ 337 region_obj2 = obj_desc->common.next_object; 338 region_obj2->extra.aml_start = aml_start; 339 region_obj2->extra.aml_length = aml_length; 340 341 /* Init the region from the operands */ 342 343 obj_desc->region.space_id = region_space; 344 obj_desc->region.address = 0; 345 obj_desc->region.length = 0; 346 obj_desc->region.node = node; 347 348 /* Install the new region object in the parent Node */ 349 350 status = acpi_ns_attach_object (node, obj_desc, ACPI_TYPE_REGION); 351 352 353cleanup: 354 355 /* Remove local reference to the object */ 356 357 acpi_ut_remove_reference (obj_desc); 358 return_ACPI_STATUS (status); 359} 360 361 362/******************************************************************************* 363 * 364 * FUNCTION: acpi_ex_create_table_region 365 * 366 * PARAMETERS: walk_state - Current state 367 * 368 * RETURN: Status 369 * 370 * DESCRIPTION: Create a new data_table_region object 371 * 372 ******************************************************************************/ 373 374acpi_status 375acpi_ex_create_table_region ( 376 struct acpi_walk_state *walk_state) 377{ 378 acpi_status status; 379 union acpi_operand_object **operand = &walk_state->operands[0]; 380 union acpi_operand_object *obj_desc; 381 struct acpi_namespace_node *node; 382 struct acpi_table_header *table; 383 union acpi_operand_object *region_obj2; 384 385 386 ACPI_FUNCTION_TRACE ("ex_create_table_region"); 387 388 389 /* Get the Node from the object stack */ 390 391 node = walk_state->op->common.node; 392 393 /* 394 * If the region object is already attached to this node, 395 * just return 396 */ 397 if (acpi_ns_get_attached_object (node)) { 398 return_ACPI_STATUS (AE_OK); 399 } 400 401 /* Find the ACPI table */ 402 403 status = acpi_tb_find_table (operand[1]->string.pointer, 404 operand[2]->string.pointer, 405 operand[3]->string.pointer, &table); 406 if (ACPI_FAILURE (status)) { 407 return_ACPI_STATUS (status); 408 } 409 410 /* Create the region descriptor */ 411 412 obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_REGION); 413 if (!obj_desc) { 414 return_ACPI_STATUS (AE_NO_MEMORY); 415 } 416 417 region_obj2 = obj_desc->common.next_object; 418 region_obj2->extra.region_context = NULL; 419 420 /* Init the region from the operands */ 421 422 obj_desc->region.space_id = REGION_DATA_TABLE; 423 obj_desc->region.address = (acpi_physical_address) ACPI_TO_INTEGER (table); 424 obj_desc->region.length = table->length; 425 obj_desc->region.node = node; 426 obj_desc->region.flags = AOPOBJ_DATA_VALID; 427 428 /* Install the new region object in the parent Node */ 429 430 status = acpi_ns_attach_object (node, obj_desc, ACPI_TYPE_REGION); 431 if (ACPI_FAILURE (status)) { 432 goto cleanup; 433 } 434 435 status = acpi_ev_initialize_region (obj_desc, FALSE); 436 if (ACPI_FAILURE (status)) { 437 if (status == AE_NOT_EXIST) { 438 status = AE_OK; 439 } 440 else { 441 goto cleanup; 442 } 443 } 444 445 obj_desc->region.flags |= AOPOBJ_SETUP_COMPLETE; 446 447 448cleanup: 449 450 /* Remove local reference to the object */ 451 452 acpi_ut_remove_reference (obj_desc); 453 return_ACPI_STATUS (status); 454} 455 456 457/******************************************************************************* 458 * 459 * FUNCTION: acpi_ex_create_processor 460 * 461 * PARAMETERS: walk_state - Current state 462 * 463 * RETURN: Status 464 * 465 * DESCRIPTION: Create a new processor object and populate the fields 466 * 467 * Processor (Name[0], cpu_iD[1], pblock_addr[2], pblock_length[3]) 468 * 469 ******************************************************************************/ 470 471acpi_status 472acpi_ex_create_processor ( 473 struct acpi_walk_state *walk_state) 474{ 475 union acpi_operand_object **operand = &walk_state->operands[0]; 476 union acpi_operand_object *obj_desc; 477 acpi_status status; 478 479 480 ACPI_FUNCTION_TRACE_PTR ("ex_create_processor", walk_state); 481 482 483 /* Create the processor object */ 484 485 obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_PROCESSOR); 486 if (!obj_desc) { 487 return_ACPI_STATUS (AE_NO_MEMORY); 488 } 489 490 /* Initialize the processor object from the operands */ 491 492 obj_desc->processor.proc_id = (u8) operand[1]->integer.value; 493 obj_desc->processor.address = (acpi_io_address) operand[2]->integer.value; 494 obj_desc->processor.length = (u8) operand[3]->integer.value; 495 496 /* Install the processor object in the parent Node */ 497 498 status = acpi_ns_attach_object ((struct acpi_namespace_node *) operand[0], 499 obj_desc, ACPI_TYPE_PROCESSOR); 500 501 /* Remove local reference to the object */ 502 503 acpi_ut_remove_reference (obj_desc); 504 return_ACPI_STATUS (status); 505} 506 507 508/******************************************************************************* 509 * 510 * FUNCTION: acpi_ex_create_power_resource 511 * 512 * PARAMETERS: walk_state - Current state 513 * 514 * RETURN: Status 515 * 516 * DESCRIPTION: Create a new power_resource object and populate the fields 517 * 518 * power_resource (Name[0], system_level[1], resource_order[2]) 519 * 520 ******************************************************************************/ 521 522acpi_status 523acpi_ex_create_power_resource ( 524 struct acpi_walk_state *walk_state) 525{ 526 union acpi_operand_object **operand = &walk_state->operands[0]; 527 acpi_status status; 528 union acpi_operand_object *obj_desc; 529 530 531 ACPI_FUNCTION_TRACE_PTR ("ex_create_power_resource", walk_state); 532 533 534 /* Create the power resource object */ 535 536 obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_POWER); 537 if (!obj_desc) { 538 return_ACPI_STATUS (AE_NO_MEMORY); 539 } 540 541 /* Initialize the power object from the operands */ 542 543 obj_desc->power_resource.system_level = (u8) operand[1]->integer.value; 544 obj_desc->power_resource.resource_order = (u16) operand[2]->integer.value; 545 546 /* Install the power resource object in the parent Node */ 547 548 status = acpi_ns_attach_object ((struct acpi_namespace_node *) operand[0], 549 obj_desc, ACPI_TYPE_POWER); 550 551 /* Remove local reference to the object */ 552 553 acpi_ut_remove_reference (obj_desc); 554 return_ACPI_STATUS (status); 555} 556#endif 557 558 559/******************************************************************************* 560 * 561 * FUNCTION: acpi_ex_create_method 562 * 563 * PARAMETERS: aml_start - First byte of the method's AML 564 * aml_length - AML byte count for this method 565 * walk_state - Current state 566 * 567 * RETURN: Status 568 * 569 * DESCRIPTION: Create a new method object 570 * 571 ******************************************************************************/ 572 573acpi_status 574acpi_ex_create_method ( 575 u8 *aml_start, 576 u32 aml_length, 577 struct acpi_walk_state *walk_state) 578{ 579 union acpi_operand_object **operand = &walk_state->operands[0]; 580 union acpi_operand_object *obj_desc; 581 acpi_status status; 582 u8 method_flags; 583 584 585 ACPI_FUNCTION_TRACE_PTR ("ex_create_method", walk_state); 586 587 588 /* Create a new method object */ 589 590 obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_METHOD); 591 if (!obj_desc) { 592 return_ACPI_STATUS (AE_NO_MEMORY); 593 } 594 595 /* Save the method's AML pointer and length */ 596 597 obj_desc->method.aml_start = aml_start; 598 obj_desc->method.aml_length = aml_length; 599 600 /* 601 * Disassemble the method flags. Split off the Arg Count 602 * for efficiency 603 */ 604 method_flags = (u8) operand[1]->integer.value; 605 606 obj_desc->method.method_flags = (u8) (method_flags & ~AML_METHOD_ARG_COUNT); 607 obj_desc->method.param_count = (u8) (method_flags & AML_METHOD_ARG_COUNT); 608 609 /* 610 * Get the concurrency count. If required, a semaphore will be 611 * created for this method when it is parsed. 612 */ 613 if (acpi_gbl_all_methods_serialized) { 614 obj_desc->method.concurrency = 1; 615 obj_desc->method.method_flags |= AML_METHOD_SERIALIZED; 616 } 617 else if (method_flags & AML_METHOD_SERIALIZED) { 618 /* 619 * ACPI 1.0: Concurrency = 1 620 * ACPI 2.0: Concurrency = (sync_level (in method declaration) + 1) 621 */ 622 obj_desc->method.concurrency = (u8) 623 (((method_flags & AML_METHOD_SYNCH_LEVEL) >> 4) + 1); 624 } 625 else { 626 obj_desc->method.concurrency = ACPI_INFINITE_CONCURRENCY; 627 } 628 629 /* Attach the new object to the method Node */ 630 631 status = acpi_ns_attach_object ((struct acpi_namespace_node *) operand[0], 632 obj_desc, ACPI_TYPE_METHOD); 633 634 /* Remove local reference to the object */ 635 636 acpi_ut_remove_reference (obj_desc); 637 638 /* Remove a reference to the operand */ 639 640 acpi_ut_remove_reference (operand[1]); 641 return_ACPI_STATUS (status); 642} 643 644