minor corrections by M.Taguchi
[reactos.git] / reactos / drivers / bus / acpi / namespace / nsload.c
1 /******************************************************************************
2 *
3 * Module Name: nsload - namespace loading/expanding/contracting procedures
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 "acinterp.h"
29 #include "acnamesp.h"
30 #include "amlcode.h"
31 #include "acparser.h"
32 #include "acdispat.h"
33 #include "acdebug.h"
34
35
36 #define _COMPONENT ACPI_NAMESPACE
37 MODULE_NAME ("nsload")
38
39
40 /*******************************************************************************
41 *
42 * FUNCTION: Acpi_load_namespace
43 *
44 * PARAMETERS: Display_aml_during_load
45 *
46 * RETURN: Status
47 *
48 * DESCRIPTION: Load the name space from what ever is pointed to by DSDT.
49 * (DSDT points to either the BIOS or a buffer.)
50 *
51 ******************************************************************************/
52
53 ACPI_STATUS
54 acpi_ns_load_namespace (
55 void)
56 {
57 ACPI_STATUS status;
58
59
60 /* There must be at least a DSDT installed */
61
62 if (acpi_gbl_DSDT == NULL) {
63 return (AE_NO_ACPI_TABLES);
64 }
65
66
67 /*
68 * Load the namespace. The DSDT is required,
69 * but the SSDT and PSDT tables are optional.
70 */
71
72 status = acpi_ns_load_table_by_type (ACPI_TABLE_DSDT);
73 if (ACPI_FAILURE (status)) {
74 return (status);
75 }
76
77 /* Ignore exceptions from these */
78
79 acpi_ns_load_table_by_type (ACPI_TABLE_SSDT);
80 acpi_ns_load_table_by_type (ACPI_TABLE_PSDT);
81
82
83 return (status);
84 }
85
86
87 /*******************************************************************************
88 *
89 * FUNCTION: Acpi_ns_one_parse_pass
90 *
91 * PARAMETERS:
92 *
93 * RETURN: Status
94 *
95 * DESCRIPTION:
96 *
97 ******************************************************************************/
98
99 ACPI_STATUS
100 acpi_ns_one_complete_parse (
101 u32 pass_number,
102 ACPI_TABLE_DESC *table_desc)
103 {
104 ACPI_PARSE_DOWNWARDS descending_callback;
105 ACPI_PARSE_UPWARDS ascending_callback;
106 ACPI_PARSE_OBJECT *parse_root;
107 ACPI_STATUS status;
108
109
110 switch (pass_number) {
111 case 1:
112 descending_callback = acpi_ds_load1_begin_op;
113 ascending_callback = acpi_ds_load1_end_op;
114 break;
115
116 case 2:
117 descending_callback = acpi_ds_load2_begin_op;
118 ascending_callback = acpi_ds_load2_end_op;
119 break;
120
121 case 3:
122 descending_callback = acpi_ds_exec_begin_op;
123 ascending_callback = acpi_ds_exec_end_op;
124 break;
125
126 default:
127 return (AE_BAD_PARAMETER);
128 }
129
130 /* Create and init a Root Node */
131
132 parse_root = acpi_ps_alloc_op (AML_SCOPE_OP);
133 if (!parse_root) {
134 return (AE_NO_MEMORY);
135 }
136
137 ((ACPI_PARSE2_OBJECT *) parse_root)->name = ACPI_ROOT_NAME;
138
139
140 /* Pass 1: Parse everything except control method bodies */
141
142 status = acpi_ps_parse_aml (parse_root, table_desc->aml_pointer,
143 table_desc->aml_length,
144 ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE,
145 NULL, NULL, NULL, descending_callback,
146 ascending_callback);
147
148 acpi_ps_delete_parse_tree (parse_root);
149
150 return (status);
151 }
152
153
154 /*******************************************************************************
155 *
156 * FUNCTION: Acpi_ns_parse_table
157 *
158 * PARAMETERS: Table_desc - An ACPI table descriptor for table to parse
159 * Start_node - Where to enter the table into the namespace
160 *
161 * RETURN: Status
162 *
163 * DESCRIPTION: Parse AML within an ACPI table and return a tree of ops
164 *
165 ******************************************************************************/
166
167 ACPI_STATUS
168 acpi_ns_parse_table (
169 ACPI_TABLE_DESC *table_desc,
170 ACPI_NAMESPACE_NODE *start_node)
171 {
172 ACPI_STATUS status;
173
174
175 /*
176 * AML Parse, pass 1
177 *
178 * In this pass, we load most of the namespace. Control methods
179 * are not parsed until later. A parse tree is not created. Instead,
180 * each Parser Op subtree is deleted when it is finished. This saves
181 * a great deal of memory, and allows a small cache of parse objects
182 * to service the entire parse. The second pass of the parse then
183 * performs another complete parse of the AML..
184 */
185
186 status = acpi_ns_one_complete_parse (1, table_desc);
187 if (ACPI_FAILURE (status)) {
188 return (status);
189 }
190
191
192 /*
193 * AML Parse, pass 2
194 *
195 * In this pass, we resolve forward references and other things
196 * that could not be completed during the first pass.
197 * Another complete parse of the AML is performed, but the
198 * overhead of this is compensated for by the fact that the
199 * parse objects are all cached.
200 */
201
202 status = acpi_ns_one_complete_parse (2, table_desc);
203 if (ACPI_FAILURE (status)) {
204 return (status);
205 }
206
207 return (status);
208 }
209
210
211 /*******************************************************************************
212 *
213 * FUNCTION: Acpi_ns_load_table
214 *
215 * PARAMETERS: *Pcode_addr - Address of pcode block
216 * Pcode_length - Length of pcode block
217 *
218 * RETURN: Status
219 *
220 * DESCRIPTION: Load one ACPI table into the namespace
221 *
222 ******************************************************************************/
223
224 ACPI_STATUS
225 acpi_ns_load_table (
226 ACPI_TABLE_DESC *table_desc,
227 ACPI_NAMESPACE_NODE *node)
228 {
229 ACPI_STATUS status;
230
231
232 if (!table_desc->aml_pointer) {
233 return (AE_BAD_PARAMETER);
234 }
235
236
237 if (!table_desc->aml_length) {
238 return (AE_BAD_PARAMETER);
239 }
240
241
242 /*
243 * Parse the table and load the namespace with all named
244 * objects found within. Control methods are NOT parsed
245 * at this time. In fact, the control methods cannot be
246 * parsed until the entire namespace is loaded, because
247 * if a control method makes a forward reference (call)
248 * to another control method, we can't continue parsing
249 * because we don't know how many arguments to parse next!
250 */
251
252 acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
253 status = acpi_ns_parse_table (table_desc, node->child);
254 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
255
256 if (ACPI_FAILURE (status)) {
257 return (status);
258 }
259
260 /*
261 * Now we can parse the control methods. We always parse
262 * them here for a sanity check, and if configured for
263 * just-in-time parsing, we delete the control method
264 * parse trees.
265 */
266
267 status = acpi_ds_initialize_objects (table_desc, node);
268
269 return (status);
270 }
271
272
273 /*******************************************************************************
274 *
275 * FUNCTION: Acpi_ns_load_table_by_type
276 *
277 * PARAMETERS: Table_type - Id of the table type to load
278 *
279 * RETURN: Status
280 *
281 * DESCRIPTION: Load an ACPI table or tables into the namespace. All tables
282 * of the given type are loaded. The mechanism allows this
283 * routine to be called repeatedly.
284 *
285 ******************************************************************************/
286
287 ACPI_STATUS
288 acpi_ns_load_table_by_type (
289 ACPI_TABLE_TYPE table_type)
290 {
291 u32 i;
292 ACPI_STATUS status = AE_OK;
293 ACPI_TABLE_HEADER *table_ptr;
294 ACPI_TABLE_DESC *table_desc;
295
296
297 acpi_cm_acquire_mutex (ACPI_MTX_TABLES);
298
299
300 /*
301 * Table types supported are:
302 * DSDT (one), SSDT/PSDT (multiple)
303 */
304
305 switch (table_type) {
306
307 case ACPI_TABLE_DSDT:
308
309 table_desc = &acpi_gbl_acpi_tables[ACPI_TABLE_DSDT];
310
311 /* If table already loaded into namespace, just return */
312
313 if (table_desc->loaded_into_namespace) {
314 goto unlock_and_exit;
315 }
316
317 table_desc->table_id = TABLE_ID_DSDT;
318
319 /* Now load the single DSDT */
320
321 status = acpi_ns_load_table (table_desc, acpi_gbl_root_node);
322 if (ACPI_SUCCESS (status)) {
323 table_desc->loaded_into_namespace = TRUE;
324 }
325
326 break;
327
328
329 case ACPI_TABLE_SSDT:
330
331 /*
332 * Traverse list of SSDT tables
333 */
334
335 table_desc = &acpi_gbl_acpi_tables[ACPI_TABLE_SSDT];
336 for (i = 0; i < acpi_gbl_acpi_tables[ACPI_TABLE_SSDT].count; i++) {
337 table_ptr = table_desc->pointer;
338
339 /*
340 * Only attempt to load table if it is not
341 * already loaded!
342 */
343
344 if (!table_desc->loaded_into_namespace) {
345 status = acpi_ns_load_table (table_desc, acpi_gbl_root_node);
346 if (ACPI_FAILURE (status)) {
347 break;
348 }
349
350 table_desc->loaded_into_namespace = TRUE;
351 }
352
353 table_desc = table_desc->next;
354 }
355 break;
356
357
358 case ACPI_TABLE_PSDT:
359
360 /*
361 * Traverse list of PSDT tables
362 */
363
364 table_desc = &acpi_gbl_acpi_tables[ACPI_TABLE_PSDT];
365
366 for (i = 0; i < acpi_gbl_acpi_tables[ACPI_TABLE_PSDT].count; i++) {
367 table_ptr = table_desc->pointer;
368
369 /* Only attempt to load table if it is not already loaded! */
370
371 if (!table_desc->loaded_into_namespace) {
372 status = acpi_ns_load_table (table_desc, acpi_gbl_root_node);
373 if (ACPI_FAILURE (status)) {
374 break;
375 }
376
377 table_desc->loaded_into_namespace = TRUE;
378 }
379
380 table_desc = table_desc->next;
381 }
382
383 break;
384
385
386 default:
387 status = AE_SUPPORT;
388 break;
389 }
390
391
392 unlock_and_exit:
393
394 acpi_cm_release_mutex (ACPI_MTX_TABLES);
395
396 return (status);
397
398 }
399
400
401 /*******************************************************************************
402 *
403 * FUNCTION: Acpi_ns_delete_subtree
404 *
405 * PARAMETERS: Start_handle - Handle in namespace where search begins
406 *
407 * RETURNS Status
408 *
409 * DESCRIPTION: Walks the namespace starting at the given handle and deletes
410 * all objects, entries, and scopes in the entire subtree.
411 *
412 * TBD: [Investigate] What if any part of this subtree is in use?
413 * (i.e. on one of the object stacks?)
414 *
415 ******************************************************************************/
416
417 ACPI_STATUS
418 acpi_ns_delete_subtree (
419 ACPI_HANDLE start_handle)
420 {
421 ACPI_STATUS status;
422 ACPI_HANDLE child_handle;
423 ACPI_HANDLE parent_handle;
424 ACPI_HANDLE next_child_handle;
425 ACPI_HANDLE dummy;
426 u32 level;
427
428
429 parent_handle = start_handle;
430 child_handle = 0;
431 level = 1;
432
433 /*
434 * Traverse the tree of objects until we bubble back up
435 * to where we started.
436 */
437
438 while (level > 0) {
439 /* Attempt to get the next object in this scope */
440
441 status = acpi_get_next_object (ACPI_TYPE_ANY, parent_handle,
442 child_handle, &next_child_handle);
443
444 child_handle = next_child_handle;
445
446
447 /* Did we get a new object? */
448
449 if (ACPI_SUCCESS (status)) {
450 /* Check if this object has any children */
451
452 if (ACPI_SUCCESS (acpi_get_next_object (ACPI_TYPE_ANY, child_handle,
453 0, &dummy))) {
454 /*
455 * There is at least one child of this object,
456 * visit the object
457 */
458
459 level++;
460 parent_handle = child_handle;
461 child_handle = 0;
462 }
463 }
464
465 else {
466 /*
467 * No more children in this object, go back up to
468 * the object's parent
469 */
470 level--;
471
472 /* Delete all children now */
473
474 acpi_ns_delete_children (child_handle);
475
476 child_handle = parent_handle;
477 acpi_get_parent (parent_handle, &parent_handle);
478 }
479 }
480
481 /* Now delete the starting object, and we are done */
482
483 acpi_ns_delete_node (child_handle);
484
485 return (AE_OK);
486 }
487
488
489 /*******************************************************************************
490 *
491 * FUNCTION: Acpi_ns_unload_name_space
492 *
493 * PARAMETERS: Handle - Root of namespace subtree to be deleted
494 *
495 * RETURN: Status
496 *
497 * DESCRIPTION: Shrinks the namespace, typically in response to an undocking
498 * event. Deletes an entire subtree starting from (and
499 * including) the given handle.
500 *
501 ******************************************************************************/
502
503 ACPI_STATUS
504 acpi_ns_unload_namespace (
505 ACPI_HANDLE handle)
506 {
507 ACPI_STATUS status;
508
509
510 /* Parameter validation */
511
512 if (!acpi_gbl_root_node) {
513 return (AE_NO_NAMESPACE);
514 }
515
516 if (!handle) {
517 return (AE_BAD_PARAMETER);
518 }
519
520
521 /* This function does the real work */
522
523 status = acpi_ns_delete_subtree (handle);
524
525 return (status);
526 }
527
528