Ported ACPI CA (from the nice guys at Intel) to ReactOS (ACPI bus driver).
[reactos.git] / reactos / drivers / bus / acpi / namespace / nsalloc.c
1 /*******************************************************************************
2 *
3 * Module Name: nsalloc - Namespace allocation and deletion utilities
4 * $Revision: 1.1 $
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