1 /*******************************************************************************
3 * Module Name: nsalloc - Namespace allocation and deletion utilities
6 ******************************************************************************/
9 * Copyright (C) 2000, 2001 R. Byron Moore
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #define _COMPONENT ACPI_NAMESPACE
33 MODULE_NAME ("nsalloc")
36 /*******************************************************************************
38 * FUNCTION: Acpi_ns_create_node
46 ******************************************************************************/
52 ACPI_NAMESPACE_NODE *node;
55 node = acpi_cm_callocate (sizeof (ACPI_NAMESPACE_NODE));
60 INCREMENT_NAME_TABLE_METRICS (sizeof (ACPI_NAMESPACE_NODE));
62 node->data_type = ACPI_DESC_TYPE_NAMED;
63 node->name = acpi_name;
64 node->reference_count = 1;
70 /*******************************************************************************
72 * FUNCTION: Acpi_ns_delete_node
80 ******************************************************************************/
84 ACPI_NAMESPACE_NODE *node)
86 ACPI_NAMESPACE_NODE *parent_node;
87 ACPI_NAMESPACE_NODE *prev_node;
88 ACPI_NAMESPACE_NODE *next_node;
91 parent_node = acpi_ns_get_parent_object (node);
94 next_node = parent_node->child;
96 while (next_node != node) {
97 prev_node = next_node;
98 next_node = prev_node->peer;
102 prev_node->peer = next_node->peer;
103 if (next_node->flags & ANOBJ_END_OF_PEER_LIST) {
104 prev_node->flags |= ANOBJ_END_OF_PEER_LIST;
108 parent_node->child = next_node->peer;
112 DECREMENT_NAME_TABLE_METRICS (sizeof (ACPI_NAMESPACE_NODE));
115 * Detach an object if there is one
119 acpi_ns_detach_object (node);
129 /*******************************************************************************
131 * FUNCTION: Acpi_ns_install_node
133 * PARAMETERS: Walk_state - Current state of the walk
134 * Parent_node - The parent of the new Node
135 * Node - The new Node to install
136 * Type - ACPI object type of the new Node
140 * DESCRIPTION: Initialize a new entry within a namespace table.
142 ******************************************************************************/
145 acpi_ns_install_node (
146 ACPI_WALK_STATE *walk_state,
147 ACPI_NAMESPACE_NODE *parent_node, /* Parent */
148 ACPI_NAMESPACE_NODE *node, /* New Child*/
149 OBJECT_TYPE_INTERNAL type)
151 u16 owner_id = TABLE_ID_DSDT;
152 ACPI_NAMESPACE_NODE *child_node;
156 * Get the owner ID from the Walk state
157 * The owner ID is used to track table deletion and
158 * deletion of objects created by methods
161 owner_id = walk_state->owner_id;
165 /* link the new entry into the parent and existing children */
167 /* TBD: Could be first, last, or alphabetic */
169 child_node = parent_node->child;
171 parent_node->child = node;
175 while (!(child_node->flags & ANOBJ_END_OF_PEER_LIST)) {
176 child_node = child_node->peer;
179 child_node->peer = node;
181 /* Clear end-of-list flag */
183 child_node->flags &= ~ANOBJ_END_OF_PEER_LIST;
186 /* Init the new entry */
188 node->owner_id = owner_id;
189 node->flags |= ANOBJ_END_OF_PEER_LIST;
190 node->peer = parent_node;
194 * If adding a name with unknown type, or having to
195 * add the region in order to define fields in it, we
196 * have a forward reference.
199 if ((ACPI_TYPE_ANY == type) ||
200 (INTERNAL_TYPE_DEF_FIELD_DEFN == type) ||
201 (INTERNAL_TYPE_BANK_FIELD_DEFN == type)) {
203 * We don't want to abort here, however!
204 * We will fill in the actual type when the
205 * real definition is found later.
211 * The Def_field_defn and Bank_field_defn cases are actually
212 * looking up the Region in which the field will be defined
215 if ((INTERNAL_TYPE_DEF_FIELD_DEFN == type) ||
216 (INTERNAL_TYPE_BANK_FIELD_DEFN == type)) {
217 type = ACPI_TYPE_REGION;
221 * Scope, Def_any, and Index_field_defn are bogus "types" which do
222 * not actually have anything to do with the type of the name
223 * being looked up. Save any other value of Type as the type of
227 if ((type != INTERNAL_TYPE_SCOPE) &&
228 (type != INTERNAL_TYPE_DEF_ANY) &&
229 (type != INTERNAL_TYPE_INDEX_FIELD_DEFN)) {
230 node->type = (u8) type;
234 * Increment the reference count(s) of all parents up to
238 while ((node = acpi_ns_get_parent_object (node)) != NULL) {
239 node->reference_count++;
246 /*******************************************************************************
248 * FUNCTION: Acpi_ns_delete_children
250 * PARAMETERS: Parent_node - Delete this objects children
254 * DESCRIPTION: Delete all children of the parent object. Deletes a
257 ******************************************************************************/
260 acpi_ns_delete_children (
261 ACPI_NAMESPACE_NODE *parent_node)
263 ACPI_NAMESPACE_NODE *child_node;
264 ACPI_NAMESPACE_NODE *next_node;
272 /* If no children, all done! */
274 child_node = parent_node->child;
280 * Deallocate all children at this level
283 /* Get the things we need */
285 next_node = child_node->peer;
286 flags = child_node->flags;
288 /* Grandchildren should have all been deleted already */
291 /* Now we can free this child object */
293 DECREMENT_NAME_TABLE_METRICS (sizeof (ACPI_NAMESPACE_NODE));
296 * Detach an object if there is one
299 if (child_node->object) {
300 acpi_ns_detach_object (child_node);
303 acpi_cm_free (child_node);
305 /* And move on to the next child in the list */
307 child_node = next_node;
309 } while (!(flags & ANOBJ_END_OF_PEER_LIST));
312 /* Clear the parent's child pointer */
314 parent_node->child = NULL;
320 /*******************************************************************************
322 * FUNCTION: Acpi_ns_delete_namespace_subtree
328 * DESCRIPTION: Delete a subtree of the namespace. This includes all objects
329 * stored within the subtree. Scope tables are deleted also
331 ******************************************************************************/
334 acpi_ns_delete_namespace_subtree (
335 ACPI_NAMESPACE_NODE *parent_node)
337 ACPI_NAMESPACE_NODE *child_node;
338 ACPI_OPERAND_OBJECT *obj_desc;
351 * Traverse the tree of objects until we bubble back up
352 * to where we started.
357 * Get the next typed object in this scope.
358 * Null returned if not found
361 child_node = acpi_ns_get_next_object (ACPI_TYPE_ANY, parent_node,
365 * Found an object - delete the object within
369 obj_desc = acpi_ns_get_attached_object (child_node);
371 acpi_ns_detach_object (child_node);
372 acpi_cm_remove_reference (obj_desc);
376 /* Check if this object has any children */
378 if (acpi_ns_get_next_object (ACPI_TYPE_ANY, child_node, 0)) {
380 * There is at least one child of this object,
385 parent_node = child_node;
392 * No more children in this object.
393 * We will move up to the grandparent.
398 * Now delete all of the children of this parent
399 * all at the same time.
401 acpi_ns_delete_children (parent_node);
403 /* New "last child" is this parent object */
405 child_node = parent_node;
407 /* Now we can move up the tree to the grandparent */
409 parent_node = acpi_ns_get_parent_object (parent_node);
418 /*******************************************************************************
420 * FUNCTION: Acpi_ns_remove_reference
422 * PARAMETERS: Node - Named object whose reference count is to be
427 * DESCRIPTION: Remove a Node reference. Decrements the reference count
428 * of all parent Nodes up to the root. Any object along
429 * the way that reaches zero references is freed.
431 ******************************************************************************/
434 acpi_ns_remove_reference (
435 ACPI_NAMESPACE_NODE *node)
437 ACPI_NAMESPACE_NODE *next_node;
441 * Decrement the reference count(s) of this object and all
442 * objects up to the root, Delete anything with zero remaining references.
446 /* Decrement the reference count on this object*/
448 next_node->reference_count--;
450 /* Delete the object if no more references */
452 if (!next_node->reference_count) {
453 /* Delete all children and delete the object */
455 acpi_ns_delete_children (next_node);
456 acpi_ns_delete_node (next_node);
459 /* Move up to parent */
461 next_node = acpi_ns_get_parent_object (next_node);
466 /*******************************************************************************
468 * FUNCTION: Acpi_ns_delete_namespace_by_owner
474 * DESCRIPTION: Delete entries within the namespace that are owned by a
475 * specific ID. Used to delete entire ACPI tables. All
476 * reference counts are updated.
478 ******************************************************************************/
481 acpi_ns_delete_namespace_by_owner (
484 ACPI_NAMESPACE_NODE *child_node;
486 ACPI_OPERAND_OBJECT *obj_desc;
487 ACPI_NAMESPACE_NODE *parent_node;
490 parent_node = acpi_gbl_root_node;
495 * Traverse the tree of objects until we bubble back up
496 * to where we started.
501 * Get the next typed object in this scope.
502 * Null returned if not found
505 child_node = acpi_ns_get_next_object (ACPI_TYPE_ANY, parent_node,
509 if (child_node->owner_id == owner_id) {
511 * Found an object - delete the object within
515 obj_desc = acpi_ns_get_attached_object (child_node);
517 acpi_ns_detach_object (child_node);
518 acpi_cm_remove_reference (obj_desc);
522 /* Check if this object has any children */
524 if (acpi_ns_get_next_object (ACPI_TYPE_ANY, child_node, 0)) {
526 * There is at least one child of this object,
531 parent_node = child_node;
535 else if (child_node->owner_id == owner_id) {
536 acpi_ns_remove_reference (child_node);
542 * No more children in this object. Move up to grandparent.
547 if (parent_node->owner_id == owner_id) {
548 acpi_ns_remove_reference (parent_node);
552 /* New "last child" is this parent object */
554 child_node = parent_node;
556 /* Now we can move up the tree to the grandparent */
558 parent_node = acpi_ns_get_parent_object (parent_node);