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