Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /****************************************************************************** |
2 | * | |
3 | * Module Name: nsinit - namespace initialization | |
4 | * | |
5 | *****************************************************************************/ | |
6 | ||
7 | /* | |
8 | * Copyright (C) 2000 - 2005, 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 | ||
45 | #include <acpi/acpi.h> | |
46 | #include <acpi/acnamesp.h> | |
47 | #include <acpi/acdispat.h> | |
48 | #include <acpi/acinterp.h> | |
49 | ||
50 | #define _COMPONENT ACPI_NAMESPACE | |
51 | ACPI_MODULE_NAME ("nsinit") | |
52 | ||
53 | ||
54 | /******************************************************************************* | |
55 | * | |
56 | * FUNCTION: acpi_ns_initialize_objects | |
57 | * | |
58 | * PARAMETERS: None | |
59 | * | |
60 | * RETURN: Status | |
61 | * | |
62 | * DESCRIPTION: Walk the entire namespace and perform any necessary | |
63 | * initialization on the objects found therein | |
64 | * | |
65 | ******************************************************************************/ | |
66 | ||
67 | acpi_status | |
68 | acpi_ns_initialize_objects ( | |
69 | void) | |
70 | { | |
71 | acpi_status status; | |
72 | struct acpi_init_walk_info info; | |
73 | ||
74 | ||
75 | ACPI_FUNCTION_TRACE ("ns_initialize_objects"); | |
76 | ||
77 | ||
78 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, | |
79 | "**** Starting initialization of namespace objects ****\n")); | |
80 | ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, | |
81 | "Completing Region/Field/Buffer/Package initialization:")); | |
82 | ||
83 | /* Set all init info to zero */ | |
84 | ||
85 | ACPI_MEMSET (&info, 0, sizeof (struct acpi_init_walk_info)); | |
86 | ||
87 | /* Walk entire namespace from the supplied root */ | |
88 | ||
89 | status = acpi_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, | |
90 | ACPI_UINT32_MAX, acpi_ns_init_one_object, | |
91 | &info, NULL); | |
92 | if (ACPI_FAILURE (status)) { | |
93 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "walk_namespace failed! %s\n", | |
94 | acpi_format_exception (status))); | |
95 | } | |
96 | ||
97 | ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, | |
98 | "\nInitialized %hd/%hd Regions %hd/%hd Fields %hd/%hd Buffers %hd/%hd Packages (%hd nodes)\n", | |
99 | info.op_region_init, info.op_region_count, | |
100 | info.field_init, info.field_count, | |
101 | info.buffer_init, info.buffer_count, | |
102 | info.package_init, info.package_count, info.object_count)); | |
103 | ||
104 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, | |
105 | "%hd Control Methods found\n", info.method_count)); | |
106 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, | |
107 | "%hd Op Regions found\n", info.op_region_count)); | |
108 | ||
109 | return_ACPI_STATUS (AE_OK); | |
110 | } | |
111 | ||
112 | ||
113 | /******************************************************************************* | |
114 | * | |
115 | * FUNCTION: acpi_ns_initialize_devices | |
116 | * | |
117 | * PARAMETERS: None | |
118 | * | |
119 | * RETURN: acpi_status | |
120 | * | |
121 | * DESCRIPTION: Walk the entire namespace and initialize all ACPI devices. | |
122 | * This means running _INI on all present devices. | |
123 | * | |
124 | * Note: We install PCI config space handler on region access, | |
125 | * not here. | |
126 | * | |
127 | ******************************************************************************/ | |
128 | ||
129 | acpi_status | |
130 | acpi_ns_initialize_devices ( | |
131 | void) | |
132 | { | |
133 | acpi_status status; | |
134 | struct acpi_device_walk_info info; | |
135 | ||
136 | ||
137 | ACPI_FUNCTION_TRACE ("ns_initialize_devices"); | |
138 | ||
139 | ||
140 | /* Init counters */ | |
141 | ||
142 | info.device_count = 0; | |
143 | info.num_STA = 0; | |
144 | info.num_INI = 0; | |
145 | ||
146 | ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, | |
147 | "Executing all Device _STA and_INI methods:")); | |
148 | ||
149 | status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); | |
150 | if (ACPI_FAILURE (status)) { | |
151 | return_ACPI_STATUS (status); | |
152 | } | |
153 | ||
154 | /* Walk namespace for all objects */ | |
155 | ||
156 | status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, | |
157 | ACPI_UINT32_MAX, TRUE, acpi_ns_init_one_device, &info, NULL); | |
158 | ||
159 | (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); | |
160 | ||
161 | if (ACPI_FAILURE (status)) { | |
162 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "walk_namespace failed! %s\n", | |
163 | acpi_format_exception (status))); | |
164 | } | |
165 | ||
166 | ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, | |
167 | "\n%hd Devices found containing: %hd _STA, %hd _INI methods\n", | |
168 | info.device_count, info.num_STA, info.num_INI)); | |
169 | ||
170 | return_ACPI_STATUS (status); | |
171 | } | |
172 | ||
173 | ||
174 | /******************************************************************************* | |
175 | * | |
176 | * FUNCTION: acpi_ns_init_one_object | |
177 | * | |
178 | * PARAMETERS: obj_handle - Node | |
179 | * Level - Current nesting level | |
180 | * Context - Points to a init info struct | |
181 | * return_value - Not used | |
182 | * | |
183 | * RETURN: Status | |
184 | * | |
185 | * DESCRIPTION: Callback from acpi_walk_namespace. Invoked for every object | |
186 | * within the namespace. | |
187 | * | |
188 | * Currently, the only objects that require initialization are: | |
189 | * 1) Methods | |
190 | * 2) Op Regions | |
191 | * | |
192 | ******************************************************************************/ | |
193 | ||
194 | acpi_status | |
195 | acpi_ns_init_one_object ( | |
196 | acpi_handle obj_handle, | |
197 | u32 level, | |
198 | void *context, | |
199 | void **return_value) | |
200 | { | |
201 | acpi_object_type type; | |
202 | acpi_status status; | |
203 | struct acpi_init_walk_info *info = (struct acpi_init_walk_info *) context; | |
204 | struct acpi_namespace_node *node = (struct acpi_namespace_node *) obj_handle; | |
205 | union acpi_operand_object *obj_desc; | |
206 | ||
207 | ||
208 | ACPI_FUNCTION_NAME ("ns_init_one_object"); | |
209 | ||
210 | ||
211 | info->object_count++; | |
212 | ||
213 | /* And even then, we are only interested in a few object types */ | |
214 | ||
215 | type = acpi_ns_get_type (obj_handle); | |
216 | obj_desc = acpi_ns_get_attached_object (node); | |
217 | if (!obj_desc) { | |
218 | return (AE_OK); | |
219 | } | |
220 | ||
221 | /* Increment counters for object types we are looking for */ | |
222 | ||
223 | switch (type) { | |
224 | case ACPI_TYPE_REGION: | |
225 | info->op_region_count++; | |
226 | break; | |
227 | ||
228 | case ACPI_TYPE_BUFFER_FIELD: | |
229 | info->field_count++; | |
230 | break; | |
231 | ||
232 | case ACPI_TYPE_BUFFER: | |
233 | info->buffer_count++; | |
234 | break; | |
235 | ||
236 | case ACPI_TYPE_PACKAGE: | |
237 | info->package_count++; | |
238 | break; | |
239 | ||
240 | default: | |
241 | ||
242 | /* No init required, just exit now */ | |
243 | return (AE_OK); | |
244 | } | |
245 | ||
246 | /* | |
247 | * If the object is already initialized, nothing else to do | |
248 | */ | |
249 | if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { | |
250 | return (AE_OK); | |
251 | } | |
252 | ||
253 | /* | |
254 | * Must lock the interpreter before executing AML code | |
255 | */ | |
256 | status = acpi_ex_enter_interpreter (); | |
257 | if (ACPI_FAILURE (status)) { | |
258 | return (status); | |
259 | } | |
260 | ||
261 | /* | |
262 | * Each of these types can contain executable AML code within the | |
263 | * declaration. | |
264 | */ | |
265 | switch (type) { | |
266 | case ACPI_TYPE_REGION: | |
267 | ||
268 | info->op_region_init++; | |
269 | status = acpi_ds_get_region_arguments (obj_desc); | |
270 | break; | |
271 | ||
272 | case ACPI_TYPE_BUFFER_FIELD: | |
273 | ||
274 | info->field_init++; | |
275 | status = acpi_ds_get_buffer_field_arguments (obj_desc); | |
276 | break; | |
277 | ||
278 | case ACPI_TYPE_BUFFER: | |
279 | ||
280 | info->buffer_init++; | |
281 | status = acpi_ds_get_buffer_arguments (obj_desc); | |
282 | break; | |
283 | ||
284 | case ACPI_TYPE_PACKAGE: | |
285 | ||
286 | info->package_init++; | |
287 | status = acpi_ds_get_package_arguments (obj_desc); | |
288 | break; | |
289 | ||
290 | default: | |
291 | /* No other types can get here */ | |
292 | break; | |
293 | } | |
294 | ||
295 | if (ACPI_FAILURE (status)) { | |
296 | ACPI_DEBUG_PRINT_RAW ((ACPI_DB_ERROR, "\n")); | |
297 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | |
298 | "Could not execute arguments for [%4.4s] (%s), %s\n", | |
299 | acpi_ut_get_node_name (node), acpi_ut_get_type_name (type), | |
300 | acpi_format_exception (status))); | |
301 | } | |
302 | ||
303 | /* | |
304 | * Print a dot for each object unless we are going to print the entire | |
305 | * pathname | |
306 | */ | |
307 | if (!(acpi_dbg_level & ACPI_LV_INIT_NAMES)) { | |
308 | ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, ".")); | |
309 | } | |
310 | ||
311 | /* | |
312 | * We ignore errors from above, and always return OK, since we don't want | |
313 | * to abort the walk on any single error. | |
314 | */ | |
315 | acpi_ex_exit_interpreter (); | |
316 | return (AE_OK); | |
317 | } | |
318 | ||
319 | ||
320 | /******************************************************************************* | |
321 | * | |
322 | * FUNCTION: acpi_ns_init_one_device | |
323 | * | |
324 | * PARAMETERS: acpi_walk_callback | |
325 | * | |
326 | * RETURN: acpi_status | |
327 | * | |
328 | * DESCRIPTION: This is called once per device soon after ACPI is enabled | |
329 | * to initialize each device. It determines if the device is | |
330 | * present, and if so, calls _INI. | |
331 | * | |
332 | ******************************************************************************/ | |
333 | ||
334 | acpi_status | |
335 | acpi_ns_init_one_device ( | |
336 | acpi_handle obj_handle, | |
337 | u32 nesting_level, | |
338 | void *context, | |
339 | void **return_value) | |
340 | { | |
341 | struct acpi_device_walk_info *info = (struct acpi_device_walk_info *) context; | |
342 | struct acpi_parameter_info pinfo; | |
343 | u32 flags; | |
344 | acpi_status status; | |
345 | ||
346 | ||
347 | ACPI_FUNCTION_TRACE ("ns_init_one_device"); | |
348 | ||
349 | ||
350 | pinfo.parameters = NULL; | |
351 | pinfo.parameter_type = ACPI_PARAM_ARGS; | |
352 | ||
353 | pinfo.node = acpi_ns_map_handle_to_node (obj_handle); | |
354 | if (!pinfo.node) { | |
355 | return_ACPI_STATUS (AE_BAD_PARAMETER); | |
356 | } | |
357 | ||
358 | /* | |
359 | * We will run _STA/_INI on Devices, Processors and thermal_zones only | |
360 | */ | |
361 | if ((pinfo.node->type != ACPI_TYPE_DEVICE) && | |
362 | (pinfo.node->type != ACPI_TYPE_PROCESSOR) && | |
363 | (pinfo.node->type != ACPI_TYPE_THERMAL)) { | |
364 | return_ACPI_STATUS (AE_OK); | |
365 | } | |
366 | ||
367 | if ((acpi_dbg_level <= ACPI_LV_ALL_EXCEPTIONS) && | |
368 | (!(acpi_dbg_level & ACPI_LV_INFO))) { | |
369 | ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, ".")); | |
370 | } | |
371 | ||
372 | info->device_count++; | |
373 | ||
374 | /* | |
375 | * Run _STA to determine if we can run _INI on the device. | |
376 | */ | |
377 | ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, pinfo.node, "_STA")); | |
378 | status = acpi_ut_execute_STA (pinfo.node, &flags); | |
379 | ||
380 | if (ACPI_FAILURE (status)) { | |
381 | if (pinfo.node->type == ACPI_TYPE_DEVICE) { | |
382 | /* Ignore error and move on to next device */ | |
383 | ||
384 | return_ACPI_STATUS (AE_OK); | |
385 | } | |
386 | ||
387 | /* _STA is not required for Processor or thermal_zone objects */ | |
388 | } | |
389 | else { | |
390 | info->num_STA++; | |
391 | ||
392 | if (!(flags & 0x01)) { | |
393 | /* Don't look at children of a not present device */ | |
394 | ||
395 | return_ACPI_STATUS(AE_CTRL_DEPTH); | |
396 | } | |
397 | } | |
398 | ||
399 | /* | |
400 | * The device is present. Run _INI. | |
401 | */ | |
402 | ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, pinfo.node, "_INI")); | |
403 | status = acpi_ns_evaluate_relative ("_INI", &pinfo); | |
404 | if (ACPI_FAILURE (status)) { | |
405 | /* No _INI (AE_NOT_FOUND) means device requires no initialization */ | |
406 | ||
407 | if (status != AE_NOT_FOUND) { | |
408 | /* Ignore error and move on to next device */ | |
409 | ||
410 | #ifdef ACPI_DEBUG_OUTPUT | |
411 | char *scope_name = acpi_ns_get_external_pathname (pinfo.node); | |
412 | ||
413 | ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "%s._INI failed: %s\n", | |
414 | scope_name, acpi_format_exception (status))); | |
415 | ||
416 | ACPI_MEM_FREE (scope_name); | |
417 | #endif | |
418 | } | |
419 | ||
420 | status = AE_OK; | |
421 | } | |
422 | else { | |
423 | /* Delete any return object (especially if implicit_return is enabled) */ | |
424 | ||
425 | if (pinfo.return_object) { | |
426 | acpi_ut_remove_reference (pinfo.return_object); | |
427 | } | |
428 | ||
429 | /* Count of successful INIs */ | |
430 | ||
431 | info->num_INI++; | |
432 | } | |
433 | ||
434 | if (acpi_gbl_init_handler) { | |
435 | /* External initialization handler is present, call it */ | |
436 | ||
437 | status = acpi_gbl_init_handler (pinfo.node, ACPI_INIT_DEVICE_INI); | |
438 | } | |
439 | ||
440 | return_ACPI_STATUS (status); | |
441 | } |