diff options
Diffstat (limited to 'drivers/acpi/acpica/evrgnini.c')
-rw-r--r-- | drivers/acpi/acpica/evrgnini.c | 684 |
1 files changed, 684 insertions, 0 deletions
diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c new file mode 100644 index 000000000000..1b7f9fdbef15 --- /dev/null +++ b/drivers/acpi/acpica/evrgnini.c | |||
@@ -0,0 +1,684 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Module Name: evrgnini- ACPI address_space (op_region) init | ||
4 | * | ||
5 | *****************************************************************************/ | ||
6 | |||
7 | /* | ||
8 | * Copyright (C) 2000 - 2008, Intel Corp. | ||
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/accommon.h> | ||
46 | #include <acpi/acevents.h> | ||
47 | #include <acpi/acnamesp.h> | ||
48 | |||
49 | #define _COMPONENT ACPI_EVENTS | ||
50 | ACPI_MODULE_NAME("evrgnini") | ||
51 | |||
52 | /* Local prototypes */ | ||
53 | static u8 acpi_ev_match_pci_root_bridge(char *id); | ||
54 | |||
55 | static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node); | ||
56 | |||
57 | /******************************************************************************* | ||
58 | * | ||
59 | * FUNCTION: acpi_ev_system_memory_region_setup | ||
60 | * | ||
61 | * PARAMETERS: Handle - Region we are interested in | ||
62 | * Function - Start or stop | ||
63 | * handler_context - Address space handler context | ||
64 | * region_context - Region specific context | ||
65 | * | ||
66 | * RETURN: Status | ||
67 | * | ||
68 | * DESCRIPTION: Setup a system_memory operation region | ||
69 | * | ||
70 | ******************************************************************************/ | ||
71 | |||
72 | acpi_status | ||
73 | acpi_ev_system_memory_region_setup(acpi_handle handle, | ||
74 | u32 function, | ||
75 | void *handler_context, void **region_context) | ||
76 | { | ||
77 | union acpi_operand_object *region_desc = | ||
78 | (union acpi_operand_object *)handle; | ||
79 | struct acpi_mem_space_context *local_region_context; | ||
80 | |||
81 | ACPI_FUNCTION_TRACE(ev_system_memory_region_setup); | ||
82 | |||
83 | if (function == ACPI_REGION_DEACTIVATE) { | ||
84 | if (*region_context) { | ||
85 | local_region_context = | ||
86 | (struct acpi_mem_space_context *)*region_context; | ||
87 | |||
88 | /* Delete a cached mapping if present */ | ||
89 | |||
90 | if (local_region_context->mapped_length) { | ||
91 | acpi_os_unmap_memory(local_region_context-> | ||
92 | mapped_logical_address, | ||
93 | local_region_context-> | ||
94 | mapped_length); | ||
95 | } | ||
96 | ACPI_FREE(local_region_context); | ||
97 | *region_context = NULL; | ||
98 | } | ||
99 | return_ACPI_STATUS(AE_OK); | ||
100 | } | ||
101 | |||
102 | /* Create a new context */ | ||
103 | |||
104 | local_region_context = | ||
105 | ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_mem_space_context)); | ||
106 | if (!(local_region_context)) { | ||
107 | return_ACPI_STATUS(AE_NO_MEMORY); | ||
108 | } | ||
109 | |||
110 | /* Save the region length and address for use in the handler */ | ||
111 | |||
112 | local_region_context->length = region_desc->region.length; | ||
113 | local_region_context->address = region_desc->region.address; | ||
114 | |||
115 | *region_context = local_region_context; | ||
116 | return_ACPI_STATUS(AE_OK); | ||
117 | } | ||
118 | |||
119 | /******************************************************************************* | ||
120 | * | ||
121 | * FUNCTION: acpi_ev_io_space_region_setup | ||
122 | * | ||
123 | * PARAMETERS: Handle - Region we are interested in | ||
124 | * Function - Start or stop | ||
125 | * handler_context - Address space handler context | ||
126 | * region_context - Region specific context | ||
127 | * | ||
128 | * RETURN: Status | ||
129 | * | ||
130 | * DESCRIPTION: Setup a IO operation region | ||
131 | * | ||
132 | ******************************************************************************/ | ||
133 | |||
134 | acpi_status | ||
135 | acpi_ev_io_space_region_setup(acpi_handle handle, | ||
136 | u32 function, | ||
137 | void *handler_context, void **region_context) | ||
138 | { | ||
139 | ACPI_FUNCTION_TRACE(ev_io_space_region_setup); | ||
140 | |||
141 | if (function == ACPI_REGION_DEACTIVATE) { | ||
142 | *region_context = NULL; | ||
143 | } else { | ||
144 | *region_context = handler_context; | ||
145 | } | ||
146 | |||
147 | return_ACPI_STATUS(AE_OK); | ||
148 | } | ||
149 | |||
150 | /******************************************************************************* | ||
151 | * | ||
152 | * FUNCTION: acpi_ev_pci_config_region_setup | ||
153 | * | ||
154 | * PARAMETERS: Handle - Region we are interested in | ||
155 | * Function - Start or stop | ||
156 | * handler_context - Address space handler context | ||
157 | * region_context - Region specific context | ||
158 | * | ||
159 | * RETURN: Status | ||
160 | * | ||
161 | * DESCRIPTION: Setup a PCI_Config operation region | ||
162 | * | ||
163 | * MUTEX: Assumes namespace is not locked | ||
164 | * | ||
165 | ******************************************************************************/ | ||
166 | |||
167 | acpi_status | ||
168 | acpi_ev_pci_config_region_setup(acpi_handle handle, | ||
169 | u32 function, | ||
170 | void *handler_context, void **region_context) | ||
171 | { | ||
172 | acpi_status status = AE_OK; | ||
173 | acpi_integer pci_value; | ||
174 | struct acpi_pci_id *pci_id = *region_context; | ||
175 | union acpi_operand_object *handler_obj; | ||
176 | struct acpi_namespace_node *parent_node; | ||
177 | struct acpi_namespace_node *pci_root_node; | ||
178 | struct acpi_namespace_node *pci_device_node; | ||
179 | union acpi_operand_object *region_obj = | ||
180 | (union acpi_operand_object *)handle; | ||
181 | |||
182 | ACPI_FUNCTION_TRACE(ev_pci_config_region_setup); | ||
183 | |||
184 | handler_obj = region_obj->region.handler; | ||
185 | if (!handler_obj) { | ||
186 | /* | ||
187 | * No installed handler. This shouldn't happen because the dispatch | ||
188 | * routine checks before we get here, but we check again just in case. | ||
189 | */ | ||
190 | ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, | ||
191 | "Attempting to init a region %p, with no handler\n", | ||
192 | region_obj)); | ||
193 | return_ACPI_STATUS(AE_NOT_EXIST); | ||
194 | } | ||
195 | |||
196 | *region_context = NULL; | ||
197 | if (function == ACPI_REGION_DEACTIVATE) { | ||
198 | if (pci_id) { | ||
199 | ACPI_FREE(pci_id); | ||
200 | } | ||
201 | return_ACPI_STATUS(status); | ||
202 | } | ||
203 | |||
204 | parent_node = acpi_ns_get_parent_node(region_obj->region.node); | ||
205 | |||
206 | /* | ||
207 | * Get the _SEG and _BBN values from the device upon which the handler | ||
208 | * is installed. | ||
209 | * | ||
210 | * We need to get the _SEG and _BBN objects relative to the PCI BUS device. | ||
211 | * This is the device the handler has been registered to handle. | ||
212 | */ | ||
213 | |||
214 | /* | ||
215 | * If the address_space.Node is still pointing to the root, we need | ||
216 | * to scan upward for a PCI Root bridge and re-associate the op_region | ||
217 | * handlers with that device. | ||
218 | */ | ||
219 | if (handler_obj->address_space.node == acpi_gbl_root_node) { | ||
220 | |||
221 | /* Start search from the parent object */ | ||
222 | |||
223 | pci_root_node = parent_node; | ||
224 | while (pci_root_node != acpi_gbl_root_node) { | ||
225 | |||
226 | /* Get the _HID/_CID in order to detect a root_bridge */ | ||
227 | |||
228 | if (acpi_ev_is_pci_root_bridge(pci_root_node)) { | ||
229 | |||
230 | /* Install a handler for this PCI root bridge */ | ||
231 | |||
232 | status = | ||
233 | acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); | ||
234 | if (ACPI_FAILURE(status)) { | ||
235 | if (status == AE_SAME_HANDLER) { | ||
236 | /* | ||
237 | * It is OK if the handler is already installed on the | ||
238 | * root bridge. Still need to return a context object | ||
239 | * for the new PCI_Config operation region, however. | ||
240 | */ | ||
241 | status = AE_OK; | ||
242 | } else { | ||
243 | ACPI_EXCEPTION((AE_INFO, status, | ||
244 | "Could not install PciConfig handler for Root Bridge %4.4s", | ||
245 | acpi_ut_get_node_name | ||
246 | (pci_root_node))); | ||
247 | } | ||
248 | } | ||
249 | break; | ||
250 | } | ||
251 | |||
252 | pci_root_node = acpi_ns_get_parent_node(pci_root_node); | ||
253 | } | ||
254 | |||
255 | /* PCI root bridge not found, use namespace root node */ | ||
256 | } else { | ||
257 | pci_root_node = handler_obj->address_space.node; | ||
258 | } | ||
259 | |||
260 | /* | ||
261 | * If this region is now initialized, we are done. | ||
262 | * (install_address_space_handler could have initialized it) | ||
263 | */ | ||
264 | if (region_obj->region.flags & AOPOBJ_SETUP_COMPLETE) { | ||
265 | return_ACPI_STATUS(AE_OK); | ||
266 | } | ||
267 | |||
268 | /* Region is still not initialized. Create a new context */ | ||
269 | |||
270 | pci_id = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pci_id)); | ||
271 | if (!pci_id) { | ||
272 | return_ACPI_STATUS(AE_NO_MEMORY); | ||
273 | } | ||
274 | |||
275 | /* | ||
276 | * For PCI_Config space access, we need the segment, bus, device and | ||
277 | * function numbers. Acquire them here. | ||
278 | * | ||
279 | * Find the parent device object. (This allows the operation region to be | ||
280 | * within a subscope under the device, such as a control method.) | ||
281 | */ | ||
282 | pci_device_node = region_obj->region.node; | ||
283 | while (pci_device_node && (pci_device_node->type != ACPI_TYPE_DEVICE)) { | ||
284 | pci_device_node = acpi_ns_get_parent_node(pci_device_node); | ||
285 | } | ||
286 | |||
287 | if (!pci_device_node) { | ||
288 | ACPI_FREE(pci_id); | ||
289 | return_ACPI_STATUS(AE_AML_OPERAND_TYPE); | ||
290 | } | ||
291 | |||
292 | /* | ||
293 | * Get the PCI device and function numbers from the _ADR object contained | ||
294 | * in the parent's scope. | ||
295 | */ | ||
296 | status = | ||
297 | acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, pci_device_node, | ||
298 | &pci_value); | ||
299 | |||
300 | /* | ||
301 | * The default is zero, and since the allocation above zeroed the data, | ||
302 | * just do nothing on failure. | ||
303 | */ | ||
304 | if (ACPI_SUCCESS(status)) { | ||
305 | pci_id->device = ACPI_HIWORD(ACPI_LODWORD(pci_value)); | ||
306 | pci_id->function = ACPI_LOWORD(ACPI_LODWORD(pci_value)); | ||
307 | } | ||
308 | |||
309 | /* The PCI segment number comes from the _SEG method */ | ||
310 | |||
311 | status = | ||
312 | acpi_ut_evaluate_numeric_object(METHOD_NAME__SEG, pci_root_node, | ||
313 | &pci_value); | ||
314 | if (ACPI_SUCCESS(status)) { | ||
315 | pci_id->segment = ACPI_LOWORD(pci_value); | ||
316 | } | ||
317 | |||
318 | /* The PCI bus number comes from the _BBN method */ | ||
319 | |||
320 | status = | ||
321 | acpi_ut_evaluate_numeric_object(METHOD_NAME__BBN, pci_root_node, | ||
322 | &pci_value); | ||
323 | if (ACPI_SUCCESS(status)) { | ||
324 | pci_id->bus = ACPI_LOWORD(pci_value); | ||
325 | } | ||
326 | |||
327 | /* Complete this device's pci_id */ | ||
328 | |||
329 | acpi_os_derive_pci_id(pci_root_node, region_obj->region.node, &pci_id); | ||
330 | |||
331 | *region_context = pci_id; | ||
332 | return_ACPI_STATUS(AE_OK); | ||
333 | } | ||
334 | |||
335 | /******************************************************************************* | ||
336 | * | ||
337 | * FUNCTION: acpi_ev_match_pci_root_bridge | ||
338 | * | ||
339 | * PARAMETERS: Id - The HID/CID in string format | ||
340 | * | ||
341 | * RETURN: TRUE if the Id is a match for a PCI/PCI-Express Root Bridge | ||
342 | * | ||
343 | * DESCRIPTION: Determine if the input ID is a PCI Root Bridge ID. | ||
344 | * | ||
345 | ******************************************************************************/ | ||
346 | |||
347 | static u8 acpi_ev_match_pci_root_bridge(char *id) | ||
348 | { | ||
349 | |||
350 | /* | ||
351 | * Check if this is a PCI root. | ||
352 | * ACPI 3.0+: check for a PCI Express root also. | ||
353 | */ | ||
354 | if (!(ACPI_STRNCMP(id, | ||
355 | PCI_ROOT_HID_STRING, | ||
356 | sizeof(PCI_ROOT_HID_STRING))) || | ||
357 | !(ACPI_STRNCMP(id, | ||
358 | PCI_EXPRESS_ROOT_HID_STRING, | ||
359 | sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) { | ||
360 | return (TRUE); | ||
361 | } | ||
362 | |||
363 | return (FALSE); | ||
364 | } | ||
365 | |||
366 | /******************************************************************************* | ||
367 | * | ||
368 | * FUNCTION: acpi_ev_is_pci_root_bridge | ||
369 | * | ||
370 | * PARAMETERS: Node - Device node being examined | ||
371 | * | ||
372 | * RETURN: TRUE if device is a PCI/PCI-Express Root Bridge | ||
373 | * | ||
374 | * DESCRIPTION: Determine if the input device represents a PCI Root Bridge by | ||
375 | * examining the _HID and _CID for the device. | ||
376 | * | ||
377 | ******************************************************************************/ | ||
378 | |||
379 | static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node) | ||
380 | { | ||
381 | acpi_status status; | ||
382 | struct acpica_device_id hid; | ||
383 | struct acpi_compatible_id_list *cid; | ||
384 | u32 i; | ||
385 | |||
386 | /* Get the _HID and check for a PCI Root Bridge */ | ||
387 | |||
388 | status = acpi_ut_execute_HID(node, &hid); | ||
389 | if (ACPI_FAILURE(status)) { | ||
390 | return (FALSE); | ||
391 | } | ||
392 | |||
393 | if (acpi_ev_match_pci_root_bridge(hid.value)) { | ||
394 | return (TRUE); | ||
395 | } | ||
396 | |||
397 | /* The _HID did not match. Get the _CID and check for a PCI Root Bridge */ | ||
398 | |||
399 | status = acpi_ut_execute_CID(node, &cid); | ||
400 | if (ACPI_FAILURE(status)) { | ||
401 | return (FALSE); | ||
402 | } | ||
403 | |||
404 | /* Check all _CIDs in the returned list */ | ||
405 | |||
406 | for (i = 0; i < cid->count; i++) { | ||
407 | if (acpi_ev_match_pci_root_bridge(cid->id[i].value)) { | ||
408 | ACPI_FREE(cid); | ||
409 | return (TRUE); | ||
410 | } | ||
411 | } | ||
412 | |||
413 | ACPI_FREE(cid); | ||
414 | return (FALSE); | ||
415 | } | ||
416 | |||
417 | /******************************************************************************* | ||
418 | * | ||
419 | * FUNCTION: acpi_ev_pci_bar_region_setup | ||
420 | * | ||
421 | * PARAMETERS: Handle - Region we are interested in | ||
422 | * Function - Start or stop | ||
423 | * handler_context - Address space handler context | ||
424 | * region_context - Region specific context | ||
425 | * | ||
426 | * RETURN: Status | ||
427 | * | ||
428 | * DESCRIPTION: Setup a pci_bAR operation region | ||
429 | * | ||
430 | * MUTEX: Assumes namespace is not locked | ||
431 | * | ||
432 | ******************************************************************************/ | ||
433 | |||
434 | acpi_status | ||
435 | acpi_ev_pci_bar_region_setup(acpi_handle handle, | ||
436 | u32 function, | ||
437 | void *handler_context, void **region_context) | ||
438 | { | ||
439 | ACPI_FUNCTION_TRACE(ev_pci_bar_region_setup); | ||
440 | |||
441 | return_ACPI_STATUS(AE_OK); | ||
442 | } | ||
443 | |||
444 | /******************************************************************************* | ||
445 | * | ||
446 | * FUNCTION: acpi_ev_cmos_region_setup | ||
447 | * | ||
448 | * PARAMETERS: Handle - Region we are interested in | ||
449 | * Function - Start or stop | ||
450 | * handler_context - Address space handler context | ||
451 | * region_context - Region specific context | ||
452 | * | ||
453 | * RETURN: Status | ||
454 | * | ||
455 | * DESCRIPTION: Setup a CMOS operation region | ||
456 | * | ||
457 | * MUTEX: Assumes namespace is not locked | ||
458 | * | ||
459 | ******************************************************************************/ | ||
460 | |||
461 | acpi_status | ||
462 | acpi_ev_cmos_region_setup(acpi_handle handle, | ||
463 | u32 function, | ||
464 | void *handler_context, void **region_context) | ||
465 | { | ||
466 | ACPI_FUNCTION_TRACE(ev_cmos_region_setup); | ||
467 | |||
468 | return_ACPI_STATUS(AE_OK); | ||
469 | } | ||
470 | |||
471 | /******************************************************************************* | ||
472 | * | ||
473 | * FUNCTION: acpi_ev_default_region_setup | ||
474 | * | ||
475 | * PARAMETERS: Handle - Region we are interested in | ||
476 | * Function - Start or stop | ||
477 | * handler_context - Address space handler context | ||
478 | * region_context - Region specific context | ||
479 | * | ||
480 | * RETURN: Status | ||
481 | * | ||
482 | * DESCRIPTION: Default region initialization | ||
483 | * | ||
484 | ******************************************************************************/ | ||
485 | |||
486 | acpi_status | ||
487 | acpi_ev_default_region_setup(acpi_handle handle, | ||
488 | u32 function, | ||
489 | void *handler_context, void **region_context) | ||
490 | { | ||
491 | ACPI_FUNCTION_TRACE(ev_default_region_setup); | ||
492 | |||
493 | if (function == ACPI_REGION_DEACTIVATE) { | ||
494 | *region_context = NULL; | ||
495 | } else { | ||
496 | *region_context = handler_context; | ||
497 | } | ||
498 | |||
499 | return_ACPI_STATUS(AE_OK); | ||
500 | } | ||
501 | |||
502 | /******************************************************************************* | ||
503 | * | ||
504 | * FUNCTION: acpi_ev_initialize_region | ||
505 | * | ||
506 | * PARAMETERS: region_obj - Region we are initializing | ||
507 | * acpi_ns_locked - Is namespace locked? | ||
508 | * | ||
509 | * RETURN: Status | ||
510 | * | ||
511 | * DESCRIPTION: Initializes the region, finds any _REG methods and saves them | ||
512 | * for execution at a later time | ||
513 | * | ||
514 | * Get the appropriate address space handler for a newly | ||
515 | * created region. | ||
516 | * | ||
517 | * This also performs address space specific initialization. For | ||
518 | * example, PCI regions must have an _ADR object that contains | ||
519 | * a PCI address in the scope of the definition. This address is | ||
520 | * required to perform an access to PCI config space. | ||
521 | * | ||
522 | * MUTEX: Interpreter should be unlocked, because we may run the _REG | ||
523 | * method for this region. | ||
524 | * | ||
525 | ******************************************************************************/ | ||
526 | |||
527 | acpi_status | ||
528 | acpi_ev_initialize_region(union acpi_operand_object *region_obj, | ||
529 | u8 acpi_ns_locked) | ||
530 | { | ||
531 | union acpi_operand_object *handler_obj; | ||
532 | union acpi_operand_object *obj_desc; | ||
533 | acpi_adr_space_type space_id; | ||
534 | struct acpi_namespace_node *node; | ||
535 | acpi_status status; | ||
536 | struct acpi_namespace_node *method_node; | ||
537 | acpi_name *reg_name_ptr = (acpi_name *) METHOD_NAME__REG; | ||
538 | union acpi_operand_object *region_obj2; | ||
539 | |||
540 | ACPI_FUNCTION_TRACE_U32(ev_initialize_region, acpi_ns_locked); | ||
541 | |||
542 | if (!region_obj) { | ||
543 | return_ACPI_STATUS(AE_BAD_PARAMETER); | ||
544 | } | ||
545 | |||
546 | if (region_obj->common.flags & AOPOBJ_OBJECT_INITIALIZED) { | ||
547 | return_ACPI_STATUS(AE_OK); | ||
548 | } | ||
549 | |||
550 | region_obj2 = acpi_ns_get_secondary_object(region_obj); | ||
551 | if (!region_obj2) { | ||
552 | return_ACPI_STATUS(AE_NOT_EXIST); | ||
553 | } | ||
554 | |||
555 | node = acpi_ns_get_parent_node(region_obj->region.node); | ||
556 | space_id = region_obj->region.space_id; | ||
557 | |||
558 | /* Setup defaults */ | ||
559 | |||
560 | region_obj->region.handler = NULL; | ||
561 | region_obj2->extra.method_REG = NULL; | ||
562 | region_obj->common.flags &= ~(AOPOBJ_SETUP_COMPLETE); | ||
563 | region_obj->common.flags |= AOPOBJ_OBJECT_INITIALIZED; | ||
564 | |||
565 | /* Find any "_REG" method associated with this region definition */ | ||
566 | |||
567 | status = | ||
568 | acpi_ns_search_one_scope(*reg_name_ptr, node, ACPI_TYPE_METHOD, | ||
569 | &method_node); | ||
570 | if (ACPI_SUCCESS(status)) { | ||
571 | /* | ||
572 | * The _REG method is optional and there can be only one per region | ||
573 | * definition. This will be executed when the handler is attached | ||
574 | * or removed | ||
575 | */ | ||
576 | region_obj2->extra.method_REG = method_node; | ||
577 | } | ||
578 | |||
579 | /* | ||
580 | * The following loop depends upon the root Node having no parent | ||
581 | * ie: acpi_gbl_root_node->parent_entry being set to NULL | ||
582 | */ | ||
583 | while (node) { | ||
584 | |||
585 | /* Check to see if a handler exists */ | ||
586 | |||
587 | handler_obj = NULL; | ||
588 | obj_desc = acpi_ns_get_attached_object(node); | ||
589 | if (obj_desc) { | ||
590 | |||
591 | /* Can only be a handler if the object exists */ | ||
592 | |||
593 | switch (node->type) { | ||
594 | case ACPI_TYPE_DEVICE: | ||
595 | |||
596 | handler_obj = obj_desc->device.handler; | ||
597 | break; | ||
598 | |||
599 | case ACPI_TYPE_PROCESSOR: | ||
600 | |||
601 | handler_obj = obj_desc->processor.handler; | ||
602 | break; | ||
603 | |||
604 | case ACPI_TYPE_THERMAL: | ||
605 | |||
606 | handler_obj = obj_desc->thermal_zone.handler; | ||
607 | break; | ||
608 | |||
609 | default: | ||
610 | /* Ignore other objects */ | ||
611 | break; | ||
612 | } | ||
613 | |||
614 | while (handler_obj) { | ||
615 | |||
616 | /* Is this handler of the correct type? */ | ||
617 | |||
618 | if (handler_obj->address_space.space_id == | ||
619 | space_id) { | ||
620 | |||
621 | /* Found correct handler */ | ||
622 | |||
623 | ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, | ||
624 | "Found handler %p for region %p in obj %p\n", | ||
625 | handler_obj, | ||
626 | region_obj, | ||
627 | obj_desc)); | ||
628 | |||
629 | status = | ||
630 | acpi_ev_attach_region(handler_obj, | ||
631 | region_obj, | ||
632 | acpi_ns_locked); | ||
633 | |||
634 | /* | ||
635 | * Tell all users that this region is usable by running the _REG | ||
636 | * method | ||
637 | */ | ||
638 | if (acpi_ns_locked) { | ||
639 | status = | ||
640 | acpi_ut_release_mutex | ||
641 | (ACPI_MTX_NAMESPACE); | ||
642 | if (ACPI_FAILURE(status)) { | ||
643 | return_ACPI_STATUS | ||
644 | (status); | ||
645 | } | ||
646 | } | ||
647 | |||
648 | status = | ||
649 | acpi_ev_execute_reg_method | ||
650 | (region_obj, 1); | ||
651 | |||
652 | if (acpi_ns_locked) { | ||
653 | status = | ||
654 | acpi_ut_acquire_mutex | ||
655 | (ACPI_MTX_NAMESPACE); | ||
656 | if (ACPI_FAILURE(status)) { | ||
657 | return_ACPI_STATUS | ||
658 | (status); | ||
659 | } | ||
660 | } | ||
661 | |||
662 | return_ACPI_STATUS(AE_OK); | ||
663 | } | ||
664 | |||
665 | /* Try next handler in the list */ | ||
666 | |||
667 | handler_obj = handler_obj->address_space.next; | ||
668 | } | ||
669 | } | ||
670 | |||
671 | /* This node does not have the handler we need; Pop up one level */ | ||
672 | |||
673 | node = acpi_ns_get_parent_node(node); | ||
674 | } | ||
675 | |||
676 | /* If we get here, there is no handler for this region */ | ||
677 | |||
678 | ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, | ||
679 | "No handler for RegionType %s(%X) (RegionObj %p)\n", | ||
680 | acpi_ut_get_region_name(space_id), space_id, | ||
681 | region_obj)); | ||
682 | |||
683 | return_ACPI_STATUS(AE_NOT_EXIST); | ||
684 | } | ||