:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / drivers / bus / acpi / namespace / nsalloc.c
1 /*******************************************************************************
2  *
3  * Module Name: nsalloc - Namespace allocation and deletion utilities
4  *              $Revision$
5  *
6  ******************************************************************************/
7
8 /*
9  *  Copyright (C) 2000, 2001 R. Byron Moore
10  *
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.
15  *
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.
20  *
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
24  */
25
26
27 #include "acpi.h"
28 #include "acnamesp.h"
29 #include "acinterp.h"
30
31
32 #define _COMPONENT          ACPI_NAMESPACE
33          MODULE_NAME         ("nsalloc")
34
35
36 /*******************************************************************************
37  *
38  * FUNCTION:    Acpi_ns_create_node
39  *
40  * PARAMETERS:
41  *
42  * RETURN:      None
43  *
44  * DESCRIPTION:
45  *
46  ******************************************************************************/
47
48 ACPI_NAMESPACE_NODE *
49 acpi_ns_create_node (
50         u32                     acpi_name)
51 {
52         ACPI_NAMESPACE_NODE     *node;
53
54
55         node = acpi_cm_callocate (sizeof (ACPI_NAMESPACE_NODE));
56         if (!node) {
57                 return (NULL);
58         }
59
60         INCREMENT_NAME_TABLE_METRICS (sizeof (ACPI_NAMESPACE_NODE));
61
62         node->data_type      = ACPI_DESC_TYPE_NAMED;
63         node->name           = acpi_name;
64         node->reference_count = 1;
65
66         return (node);
67 }
68
69
70 /*******************************************************************************
71  *
72  * FUNCTION:    Acpi_ns_delete_node
73  *
74  * PARAMETERS:
75  *
76  * RETURN:      None
77  *
78  * DESCRIPTION:
79  *
80  ******************************************************************************/
81
82 void
83 acpi_ns_delete_node (
84         ACPI_NAMESPACE_NODE     *node)
85 {
86         ACPI_NAMESPACE_NODE     *parent_node;
87         ACPI_NAMESPACE_NODE     *prev_node;
88         ACPI_NAMESPACE_NODE     *next_node;
89
90
91         parent_node = acpi_ns_get_parent_object (node);
92
93         prev_node = NULL;
94         next_node = parent_node->child;
95
96         while (next_node != node) {
97                 prev_node = next_node;
98                 next_node = prev_node->peer;
99         }
100
101         if (prev_node) {
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;
105                 }
106         }
107         else {
108                 parent_node->child = next_node->peer;
109         }
110
111
112         DECREMENT_NAME_TABLE_METRICS (sizeof (ACPI_NAMESPACE_NODE));
113
114         /*
115          * Detach an object if there is one
116          */
117
118         if (node->object) {
119                 acpi_ns_detach_object (node);
120         }
121
122         acpi_cm_free (node);
123
124
125         return;
126 }
127
128
129 /*******************************************************************************
130  *
131  * FUNCTION:    Acpi_ns_install_node
132  *
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
137  *
138  * RETURN:      None
139  *
140  * DESCRIPTION: Initialize a new entry within a namespace table.
141  *
142  ******************************************************************************/
143
144 void
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)
150 {
151         u16                     owner_id = TABLE_ID_DSDT;
152         ACPI_NAMESPACE_NODE     *child_node;
153
154
155         /*
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
159          */
160         if (walk_state) {
161                 owner_id = walk_state->owner_id;
162         }
163
164
165         /* link the new entry into the parent and existing children */
166
167         /* TBD: Could be first, last, or alphabetic */
168
169         child_node = parent_node->child;
170         if (!child_node) {
171                 parent_node->child = node;
172         }
173
174         else {
175                 while (!(child_node->flags & ANOBJ_END_OF_PEER_LIST)) {
176                         child_node = child_node->peer;
177                 }
178
179                 child_node->peer = node;
180
181                 /* Clear end-of-list flag */
182
183                 child_node->flags &= ~ANOBJ_END_OF_PEER_LIST;
184         }
185
186         /* Init the new entry */
187
188         node->owner_id  = owner_id;
189         node->flags     |= ANOBJ_END_OF_PEER_LIST;
190         node->peer      = parent_node;
191
192
193         /*
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.
197          */
198
199         if ((ACPI_TYPE_ANY == type) ||
200                 (INTERNAL_TYPE_DEF_FIELD_DEFN == type) ||
201                 (INTERNAL_TYPE_BANK_FIELD_DEFN == type)) {
202                 /*
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.
206                  */
207
208         }
209
210         /*
211          * The Def_field_defn and Bank_field_defn cases are actually
212          * looking up the Region in which the field will be defined
213          */
214
215         if ((INTERNAL_TYPE_DEF_FIELD_DEFN == type) ||
216                 (INTERNAL_TYPE_BANK_FIELD_DEFN == type)) {
217                 type = ACPI_TYPE_REGION;
218         }
219
220         /*
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
224          * the entry.
225          */
226
227         if ((type != INTERNAL_TYPE_SCOPE) &&
228                 (type != INTERNAL_TYPE_DEF_ANY) &&
229                 (type != INTERNAL_TYPE_INDEX_FIELD_DEFN)) {
230                 node->type = (u8) type;
231         }
232
233         /*
234          * Increment the reference count(s) of all parents up to
235          * the root!
236          */
237
238         while ((node = acpi_ns_get_parent_object (node)) != NULL) {
239                 node->reference_count++;
240         }
241
242         return;
243 }
244
245
246 /*******************************************************************************
247  *
248  * FUNCTION:    Acpi_ns_delete_children
249  *
250  * PARAMETERS:  Parent_node     - Delete this objects children
251  *
252  * RETURN:      None.
253  *
254  * DESCRIPTION: Delete all children of the parent object. Deletes a
255  *              "scope".
256  *
257  ******************************************************************************/
258
259 void
260 acpi_ns_delete_children (
261         ACPI_NAMESPACE_NODE     *parent_node)
262 {
263         ACPI_NAMESPACE_NODE     *child_node;
264         ACPI_NAMESPACE_NODE     *next_node;
265         u8                      flags;
266
267
268         if (!parent_node) {
269                 return;
270         }
271
272         /* If no children, all done! */
273
274         child_node = parent_node->child;
275         if (!child_node) {
276                 return;
277         }
278
279         /*
280          * Deallocate all children at this level
281          */
282         do {
283                 /* Get the things we need */
284
285                 next_node   = child_node->peer;
286                 flags       = child_node->flags;
287
288                 /* Grandchildren should have all been deleted already */
289
290
291                 /* Now we can free this child object */
292
293                 DECREMENT_NAME_TABLE_METRICS (sizeof (ACPI_NAMESPACE_NODE));
294
295                 /*
296                  * Detach an object if there is one
297                  */
298
299                 if (child_node->object) {
300                         acpi_ns_detach_object (child_node);
301                 }
302
303                 acpi_cm_free (child_node);
304
305                 /* And move on to the next child in the list */
306
307                 child_node = next_node;
308
309         } while (!(flags & ANOBJ_END_OF_PEER_LIST));
310
311
312         /* Clear the parent's child pointer */
313
314         parent_node->child = NULL;
315
316         return;
317 }
318
319
320 /*******************************************************************************
321  *
322  * FUNCTION:    Acpi_ns_delete_namespace_subtree
323  *
324  * PARAMETERS:  None.
325  *
326  * RETURN:      None.
327  *
328  * DESCRIPTION: Delete a subtree of the namespace.  This includes all objects
329  *              stored within the subtree.  Scope tables are deleted also
330  *
331  ******************************************************************************/
332
333 ACPI_STATUS
334 acpi_ns_delete_namespace_subtree (
335         ACPI_NAMESPACE_NODE     *parent_node)
336 {
337         ACPI_NAMESPACE_NODE     *child_node;
338         ACPI_OPERAND_OBJECT     *obj_desc;
339         u32                     level;
340
341
342         if (!parent_node) {
343                 return (AE_OK);
344         }
345
346
347         child_node  = 0;
348         level       = 1;
349
350         /*
351          * Traverse the tree of objects until we bubble back up
352          * to where we started.
353          */
354
355         while (level > 0) {
356                 /*
357                  * Get the next typed object in this scope.
358                  * Null returned if not found
359                  */
360
361                 child_node = acpi_ns_get_next_object (ACPI_TYPE_ANY, parent_node,
362                                  child_node);
363                 if (child_node) {
364                         /*
365                          * Found an object - delete the object within
366                          * the Value field
367                          */
368
369                         obj_desc = acpi_ns_get_attached_object (child_node);
370                         if (obj_desc) {
371                                 acpi_ns_detach_object (child_node);
372                                 acpi_cm_remove_reference (obj_desc);
373                         }
374
375
376                         /* Check if this object has any children */
377
378                         if (acpi_ns_get_next_object (ACPI_TYPE_ANY, child_node, 0)) {
379                                 /*
380                                  * There is at least one child of this object,
381                                  * visit the object
382                                  */
383
384                                 level++;
385                                 parent_node   = child_node;
386                                 child_node    = 0;
387                         }
388                 }
389
390                 else {
391                         /*
392                          * No more children in this object.
393                          * We will move up to the grandparent.
394                          */
395                         level--;
396
397                         /*
398                          * Now delete all of the children of this parent
399                          * all at the same time.
400                          */
401                         acpi_ns_delete_children (parent_node);
402
403                         /* New "last child" is this parent object */
404
405                         child_node = parent_node;
406
407                         /* Now we can move up the tree to the grandparent */
408
409                         parent_node = acpi_ns_get_parent_object (parent_node);
410                 }
411         }
412
413
414         return (AE_OK);
415 }
416
417
418 /*******************************************************************************
419  *
420  * FUNCTION:    Acpi_ns_remove_reference
421  *
422  * PARAMETERS:  Node           - Named object whose reference count is to be
423  *                                decremented
424  *
425  * RETURN:      None.
426  *
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.
430  *
431  ******************************************************************************/
432
433 static void
434 acpi_ns_remove_reference (
435         ACPI_NAMESPACE_NODE     *node)
436 {
437         ACPI_NAMESPACE_NODE     *next_node;
438
439
440         /*
441          * Decrement the reference count(s) of this object and all
442          * objects up to the root,  Delete anything with zero remaining references.
443          */
444         next_node = node;
445         while (next_node) {
446                 /* Decrement the reference count on this object*/
447
448                 next_node->reference_count--;
449
450                 /* Delete the object if no more references */
451
452                 if (!next_node->reference_count) {
453                         /* Delete all children and delete the object */
454
455                         acpi_ns_delete_children (next_node);
456                         acpi_ns_delete_node (next_node);
457                 }
458
459                 /* Move up to parent */
460
461                 next_node = acpi_ns_get_parent_object (next_node);
462         }
463 }
464
465
466 /*******************************************************************************
467  *
468  * FUNCTION:    Acpi_ns_delete_namespace_by_owner
469  *
470  * PARAMETERS:  None.
471  *
472  * RETURN:      None.
473  *
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.
477  *
478  ******************************************************************************/
479
480 ACPI_STATUS
481 acpi_ns_delete_namespace_by_owner (
482         u16                     owner_id)
483 {
484         ACPI_NAMESPACE_NODE     *child_node;
485         u32                     level;
486         ACPI_OPERAND_OBJECT     *obj_desc;
487         ACPI_NAMESPACE_NODE     *parent_node;
488
489
490         parent_node = acpi_gbl_root_node;
491         child_node  = 0;
492         level       = 1;
493
494         /*
495          * Traverse the tree of objects until we bubble back up
496          * to where we started.
497          */
498
499         while (level > 0) {
500                 /*
501                  * Get the next typed object in this scope.
502                  * Null returned if not found
503                  */
504
505                 child_node = acpi_ns_get_next_object (ACPI_TYPE_ANY, parent_node,
506                                  child_node);
507
508                 if (child_node) {
509                         if (child_node->owner_id == owner_id) {
510                                 /*
511                                  * Found an object - delete the object within
512                                  * the Value field
513                                  */
514
515                                 obj_desc = acpi_ns_get_attached_object (child_node);
516                                 if (obj_desc) {
517                                         acpi_ns_detach_object (child_node);
518                                         acpi_cm_remove_reference (obj_desc);
519                                 }
520                         }
521
522                         /* Check if this object has any children */
523
524                         if (acpi_ns_get_next_object (ACPI_TYPE_ANY, child_node, 0)) {
525                                 /*
526                                  * There is at least one child of this object,
527                                  * visit the object
528                                  */
529
530                                 level++;
531                                 parent_node   = child_node;
532                                 child_node    = 0;
533                         }
534
535                         else if (child_node->owner_id == owner_id) {
536                                 acpi_ns_remove_reference (child_node);
537                         }
538                 }
539
540                 else {
541                         /*
542                          * No more children in this object.  Move up to grandparent.
543                          */
544                         level--;
545
546                         if (level != 0) {
547                                 if (parent_node->owner_id == owner_id) {
548                                         acpi_ns_remove_reference (parent_node);
549                                 }
550                         }
551
552                         /* New "last child" is this parent object */
553
554                         child_node = parent_node;
555
556                         /* Now we can move up the tree to the grandparent */
557
558                         parent_node = acpi_ns_get_parent_object (parent_node);
559                 }
560         }
561
562
563         return (AE_OK);
564 }
565
566