]> err.no Git - linux-2.6/blob - drivers/acpi/namespace/nsload.c
Merge branch 'upstream' of git://lost.foo-projects.org/~ahkok/git/netdev-2.6 into...
[linux-2.6] / drivers / acpi / namespace / nsload.c
1 /******************************************************************************
2  *
3  * Module Name: nsload - namespace loading/expanding/contracting procedures
4  *
5  *****************************************************************************/
6
7 /*
8  * Copyright (C) 2000 - 2006, R. Byron Moore
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43
44 #include <acpi/acpi.h>
45 #include <acpi/acnamesp.h>
46 #include <acpi/acdispat.h>
47
48 #define _COMPONENT          ACPI_NAMESPACE
49 ACPI_MODULE_NAME("nsload")
50
51 /* Local prototypes */
52 static acpi_status acpi_ns_load_table_by_type(acpi_table_type table_type);
53
54 #ifdef ACPI_FUTURE_IMPLEMENTATION
55 acpi_status acpi_ns_unload_namespace(acpi_handle handle);
56
57 static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle);
58 #endif
59
60 #ifndef ACPI_NO_METHOD_EXECUTION
61 /*******************************************************************************
62  *
63  * FUNCTION:    acpi_ns_load_table
64  *
65  * PARAMETERS:  table_desc      - Descriptor for table to be loaded
66  *              Node            - Owning NS node
67  *
68  * RETURN:      Status
69  *
70  * DESCRIPTION: Load one ACPI table into the namespace
71  *
72  ******************************************************************************/
73
74 acpi_status
75 acpi_ns_load_table(struct acpi_table_desc *table_desc,
76                    struct acpi_namespace_node *node)
77 {
78         acpi_status status;
79
80         ACPI_FUNCTION_TRACE(ns_load_table);
81
82         /* Check if table contains valid AML (must be DSDT, PSDT, SSDT, etc.) */
83
84         if (!
85             (acpi_gbl_table_data[table_desc->type].
86              flags & ACPI_TABLE_EXECUTABLE)) {
87
88                 /* Just ignore this table */
89
90                 return_ACPI_STATUS(AE_OK);
91         }
92
93         /* Check validity of the AML start and length */
94
95         if (!table_desc->aml_start) {
96                 ACPI_ERROR((AE_INFO, "Null AML pointer"));
97                 return_ACPI_STATUS(AE_BAD_PARAMETER);
98         }
99
100         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "AML block at %p\n",
101                           table_desc->aml_start));
102
103         /* Ignore table if there is no AML contained within */
104
105         if (!table_desc->aml_length) {
106                 ACPI_WARNING((AE_INFO, "Zero-length AML block in table [%4.4s]",
107                               table_desc->pointer->signature));
108                 return_ACPI_STATUS(AE_OK);
109         }
110
111         /*
112          * Parse the table and load the namespace with all named
113          * objects found within.  Control methods are NOT parsed
114          * at this time.  In fact, the control methods cannot be
115          * parsed until the entire namespace is loaded, because
116          * if a control method makes a forward reference (call)
117          * to another control method, we can't continue parsing
118          * because we don't know how many arguments to parse next!
119          */
120         ACPI_DEBUG_PRINT((ACPI_DB_INFO,
121                           "**** Loading table into namespace ****\n"));
122
123         status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
124         if (ACPI_FAILURE(status)) {
125                 return_ACPI_STATUS(status);
126         }
127
128         status = acpi_ns_parse_table(table_desc, node->child);
129         (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
130
131         if (ACPI_FAILURE(status)) {
132                 return_ACPI_STATUS(status);
133         }
134
135         /*
136          * Now we can parse the control methods.  We always parse
137          * them here for a sanity check, and if configured for
138          * just-in-time parsing, we delete the control method
139          * parse trees.
140          */
141         ACPI_DEBUG_PRINT((ACPI_DB_INFO,
142                           "**** Begin Table Method Parsing and Object Initialization ****\n"));
143
144         status = acpi_ds_initialize_objects(table_desc, node);
145
146         ACPI_DEBUG_PRINT((ACPI_DB_INFO,
147                           "**** Completed Table Method Parsing and Object Initialization ****\n"));
148
149         return_ACPI_STATUS(status);
150 }
151
152 /*******************************************************************************
153  *
154  * FUNCTION:    acpi_ns_load_table_by_type
155  *
156  * PARAMETERS:  table_type          - Id of the table type to load
157  *
158  * RETURN:      Status
159  *
160  * DESCRIPTION: Load an ACPI table or tables into the namespace.  All tables
161  *              of the given type are loaded.  The mechanism allows this
162  *              routine to be called repeatedly.
163  *
164  ******************************************************************************/
165
166 static acpi_status acpi_ns_load_table_by_type(acpi_table_type table_type)
167 {
168         u32 i;
169         acpi_status status;
170         struct acpi_table_desc *table_desc;
171
172         ACPI_FUNCTION_TRACE(ns_load_table_by_type);
173
174         status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
175         if (ACPI_FAILURE(status)) {
176                 return_ACPI_STATUS(status);
177         }
178
179         /*
180          * Table types supported are:
181          * DSDT (one), SSDT/PSDT (multiple)
182          */
183         switch (table_type) {
184         case ACPI_TABLE_ID_DSDT:
185
186                 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Namespace load: DSDT\n"));
187
188                 table_desc = acpi_gbl_table_lists[ACPI_TABLE_ID_DSDT].next;
189
190                 /* If table already loaded into namespace, just return */
191
192                 if (table_desc->loaded_into_namespace) {
193                         goto unlock_and_exit;
194                 }
195
196                 /* Now load the single DSDT */
197
198                 status = acpi_ns_load_table(table_desc, acpi_gbl_root_node);
199                 if (ACPI_SUCCESS(status)) {
200                         table_desc->loaded_into_namespace = TRUE;
201                 }
202                 break;
203
204         case ACPI_TABLE_ID_SSDT:
205         case ACPI_TABLE_ID_PSDT:
206
207                 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
208                                   "Namespace load: %d SSDT or PSDTs\n",
209                                   acpi_gbl_table_lists[table_type].count));
210
211                 /*
212                  * Traverse list of SSDT or PSDT tables
213                  */
214                 table_desc = acpi_gbl_table_lists[table_type].next;
215                 for (i = 0; i < acpi_gbl_table_lists[table_type].count; i++) {
216                         /*
217                          * Only attempt to load table into namespace if it is not
218                          * already loaded!
219                          */
220                         if (!table_desc->loaded_into_namespace) {
221                                 status =
222                                     acpi_ns_load_table(table_desc,
223                                                        acpi_gbl_root_node);
224                                 if (ACPI_FAILURE(status)) {
225                                         break;
226                                 }
227
228                                 table_desc->loaded_into_namespace = TRUE;
229                         }
230
231                         table_desc = table_desc->next;
232                 }
233                 break;
234
235         default:
236                 status = AE_SUPPORT;
237                 break;
238         }
239
240       unlock_and_exit:
241         (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
242         return_ACPI_STATUS(status);
243 }
244
245 /*******************************************************************************
246  *
247  * FUNCTION:    acpi_load_namespace
248  *
249  * PARAMETERS:  None
250  *
251  * RETURN:      Status
252  *
253  * DESCRIPTION: Load the name space from what ever is pointed to by DSDT.
254  *              (DSDT points to either the BIOS or a buffer.)
255  *
256  ******************************************************************************/
257
258 acpi_status acpi_ns_load_namespace(void)
259 {
260         acpi_status status;
261
262         ACPI_FUNCTION_TRACE(acpi_load_name_space);
263
264         /* There must be at least a DSDT installed */
265
266         if (acpi_gbl_DSDT == NULL) {
267                 ACPI_ERROR((AE_INFO, "DSDT is not in memory"));
268                 return_ACPI_STATUS(AE_NO_ACPI_TABLES);
269         }
270
271         /*
272          * Load the namespace.  The DSDT is required,
273          * but the SSDT and PSDT tables are optional.
274          */
275         status = acpi_ns_load_table_by_type(ACPI_TABLE_ID_DSDT);
276         if (ACPI_FAILURE(status)) {
277                 return_ACPI_STATUS(status);
278         }
279
280         /* Ignore exceptions from these */
281
282         (void)acpi_ns_load_table_by_type(ACPI_TABLE_ID_SSDT);
283         (void)acpi_ns_load_table_by_type(ACPI_TABLE_ID_PSDT);
284
285         ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
286                               "ACPI Namespace successfully loaded at root %p\n",
287                               acpi_gbl_root_node));
288
289         return_ACPI_STATUS(status);
290 }
291
292 #ifdef ACPI_FUTURE_IMPLEMENTATION
293 /*******************************************************************************
294  *
295  * FUNCTION:    acpi_ns_delete_subtree
296  *
297  * PARAMETERS:  start_handle        - Handle in namespace where search begins
298  *
299  * RETURNS      Status
300  *
301  * DESCRIPTION: Walks the namespace starting at the given handle and deletes
302  *              all objects, entries, and scopes in the entire subtree.
303  *
304  *              Namespace/Interpreter should be locked or the subsystem should
305  *              be in shutdown before this routine is called.
306  *
307  ******************************************************************************/
308
309 static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle)
310 {
311         acpi_status status;
312         acpi_handle child_handle;
313         acpi_handle parent_handle;
314         acpi_handle next_child_handle;
315         acpi_handle dummy;
316         u32 level;
317
318         ACPI_FUNCTION_TRACE(ns_delete_subtree);
319
320         parent_handle = start_handle;
321         child_handle = NULL;
322         level = 1;
323
324         /*
325          * Traverse the tree of objects until we bubble back up
326          * to where we started.
327          */
328         while (level > 0) {
329
330                 /* Attempt to get the next object in this scope */
331
332                 status = acpi_get_next_object(ACPI_TYPE_ANY, parent_handle,
333                                               child_handle, &next_child_handle);
334
335                 child_handle = next_child_handle;
336
337                 /* Did we get a new object? */
338
339                 if (ACPI_SUCCESS(status)) {
340
341                         /* Check if this object has any children */
342
343                         if (ACPI_SUCCESS
344                             (acpi_get_next_object
345                              (ACPI_TYPE_ANY, child_handle, NULL, &dummy))) {
346                                 /*
347                                  * There is at least one child of this object,
348                                  * visit the object
349                                  */
350                                 level++;
351                                 parent_handle = child_handle;
352                                 child_handle = NULL;
353                         }
354                 } else {
355                         /*
356                          * No more children in this object, go back up to
357                          * the object's parent
358                          */
359                         level--;
360
361                         /* Delete all children now */
362
363                         acpi_ns_delete_children(child_handle);
364
365                         child_handle = parent_handle;
366                         status = acpi_get_parent(parent_handle, &parent_handle);
367                         if (ACPI_FAILURE(status)) {
368                                 return_ACPI_STATUS(status);
369                         }
370                 }
371         }
372
373         /* Now delete the starting object, and we are done */
374
375         acpi_ns_delete_node(child_handle);
376
377         return_ACPI_STATUS(AE_OK);
378 }
379
380 /*******************************************************************************
381  *
382  *  FUNCTION:       acpi_ns_unload_name_space
383  *
384  *  PARAMETERS:     Handle          - Root of namespace subtree to be deleted
385  *
386  *  RETURN:         Status
387  *
388  *  DESCRIPTION:    Shrinks the namespace, typically in response to an undocking
389  *                  event.  Deletes an entire subtree starting from (and
390  *                  including) the given handle.
391  *
392  ******************************************************************************/
393
394 acpi_status acpi_ns_unload_namespace(acpi_handle handle)
395 {
396         acpi_status status;
397
398         ACPI_FUNCTION_TRACE(ns_unload_name_space);
399
400         /* Parameter validation */
401
402         if (!acpi_gbl_root_node) {
403                 return_ACPI_STATUS(AE_NO_NAMESPACE);
404         }
405
406         if (!handle) {
407                 return_ACPI_STATUS(AE_BAD_PARAMETER);
408         }
409
410         /* This function does the real work */
411
412         status = acpi_ns_delete_subtree(handle);
413
414         return_ACPI_STATUS(status);
415 }
416 #endif
417 #endif