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
);