Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6595 | serge | 1 | /****************************************************************************** |
2 | * |
||
3 | * Module Name: evregion - Operation Region support |
||
4 | * |
||
5 | *****************************************************************************/ |
||
6 | |||
7 | /* |
||
8 | * Copyright (C) 2000 - 2015, 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 |
||
45 | #include "accommon.h" |
||
46 | #include "acevents.h" |
||
47 | #include "acnamesp.h" |
||
48 | #include "acinterp.h" |
||
49 | |||
50 | #define _COMPONENT ACPI_EVENTS |
||
51 | ACPI_MODULE_NAME("evregion") |
||
52 | |||
53 | extern u8 acpi_gbl_default_address_spaces[]; |
||
54 | |||
55 | /* Local prototypes */ |
||
56 | |||
57 | static void |
||
58 | acpi_ev_orphan_ec_reg_method(struct acpi_namespace_node *ec_device_node); |
||
59 | |||
60 | static acpi_status |
||
61 | acpi_ev_reg_run(acpi_handle obj_handle, |
||
62 | u32 level, void *context, void **return_value); |
||
63 | |||
64 | /******************************************************************************* |
||
65 | * |
||
66 | * FUNCTION: acpi_ev_initialize_op_regions |
||
67 | * |
||
68 | * PARAMETERS: None |
||
69 | * |
||
70 | * RETURN: Status |
||
71 | * |
||
72 | * DESCRIPTION: Execute _REG methods for all Operation Regions that have |
||
73 | * an installed default region handler. |
||
74 | * |
||
75 | ******************************************************************************/ |
||
76 | |||
77 | acpi_status acpi_ev_initialize_op_regions(void) |
||
78 | { |
||
79 | acpi_status status; |
||
80 | u32 i; |
||
81 | |||
82 | ACPI_FUNCTION_TRACE(ev_initialize_op_regions); |
||
83 | |||
84 | status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
||
85 | if (ACPI_FAILURE(status)) { |
||
86 | return_ACPI_STATUS(status); |
||
87 | } |
||
88 | |||
89 | /* Run the _REG methods for op_regions in each default address space */ |
||
90 | |||
91 | for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) { |
||
92 | /* |
||
93 | * Make sure the installed handler is the DEFAULT handler. If not the |
||
94 | * default, the _REG methods will have already been run (when the |
||
95 | * handler was installed) |
||
96 | */ |
||
97 | if (acpi_ev_has_default_handler(acpi_gbl_root_node, |
||
98 | acpi_gbl_default_address_spaces |
||
99 | [i])) { |
||
100 | status = |
||
101 | acpi_ev_execute_reg_methods(acpi_gbl_root_node, |
||
102 | acpi_gbl_default_address_spaces |
||
103 | [i]); |
||
104 | } |
||
105 | } |
||
106 | |||
107 | acpi_gbl_reg_methods_executed = TRUE; |
||
108 | |||
109 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
||
110 | return_ACPI_STATUS(status); |
||
111 | } |
||
112 | |||
113 | /******************************************************************************* |
||
114 | * |
||
115 | * FUNCTION: acpi_ev_address_space_dispatch |
||
116 | * |
||
117 | * PARAMETERS: region_obj - Internal region object |
||
118 | * field_obj - Corresponding field. Can be NULL. |
||
119 | * function - Read or Write operation |
||
120 | * region_offset - Where in the region to read or write |
||
121 | * bit_width - Field width in bits (8, 16, 32, or 64) |
||
122 | * value - Pointer to in or out value, must be |
||
123 | * a full 64-bit integer |
||
124 | * |
||
125 | * RETURN: Status |
||
126 | * |
||
127 | * DESCRIPTION: Dispatch an address space or operation region access to |
||
128 | * a previously installed handler. |
||
129 | * |
||
130 | ******************************************************************************/ |
||
131 | |||
132 | acpi_status |
||
133 | acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, |
||
134 | union acpi_operand_object *field_obj, |
||
135 | u32 function, |
||
136 | u32 region_offset, u32 bit_width, u64 *value) |
||
137 | { |
||
138 | acpi_status status; |
||
139 | acpi_adr_space_handler handler; |
||
140 | acpi_adr_space_setup region_setup; |
||
141 | union acpi_operand_object *handler_desc; |
||
142 | union acpi_operand_object *region_obj2; |
||
143 | void *region_context = NULL; |
||
144 | struct acpi_connection_info *context; |
||
145 | acpi_physical_address address; |
||
146 | |||
147 | ACPI_FUNCTION_TRACE(ev_address_space_dispatch); |
||
148 | |||
149 | region_obj2 = acpi_ns_get_secondary_object(region_obj); |
||
150 | if (!region_obj2) { |
||
151 | return_ACPI_STATUS(AE_NOT_EXIST); |
||
152 | } |
||
153 | |||
154 | /* Ensure that there is a handler associated with this region */ |
||
155 | |||
156 | handler_desc = region_obj->region.handler; |
||
157 | if (!handler_desc) { |
||
158 | ACPI_ERROR((AE_INFO, |
||
159 | "No handler for Region [%4.4s] (%p) [%s]", |
||
160 | acpi_ut_get_node_name(region_obj->region.node), |
||
161 | region_obj, |
||
162 | acpi_ut_get_region_name(region_obj->region. |
||
163 | space_id))); |
||
164 | |||
165 | return_ACPI_STATUS(AE_NOT_EXIST); |
||
166 | } |
||
167 | |||
168 | context = handler_desc->address_space.context; |
||
169 | |||
170 | /* |
||
171 | * It may be the case that the region has never been initialized. |
||
172 | * Some types of regions require special init code |
||
173 | */ |
||
174 | if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) { |
||
175 | |||
176 | /* This region has not been initialized yet, do it */ |
||
177 | |||
178 | region_setup = handler_desc->address_space.setup; |
||
179 | if (!region_setup) { |
||
180 | |||
181 | /* No initialization routine, exit with error */ |
||
182 | |||
183 | ACPI_ERROR((AE_INFO, |
||
184 | "No init routine for region(%p) [%s]", |
||
185 | region_obj, |
||
186 | acpi_ut_get_region_name(region_obj->region. |
||
187 | space_id))); |
||
188 | return_ACPI_STATUS(AE_NOT_EXIST); |
||
189 | } |
||
190 | |||
191 | /* |
||
192 | * We must exit the interpreter because the region setup will |
||
193 | * potentially execute control methods (for example, the _REG method |
||
194 | * for this region) |
||
195 | */ |
||
196 | acpi_ex_exit_interpreter(); |
||
197 | |||
198 | status = region_setup(region_obj, ACPI_REGION_ACTIVATE, |
||
199 | context, ®ion_context); |
||
200 | |||
201 | /* Re-enter the interpreter */ |
||
202 | |||
203 | acpi_ex_enter_interpreter(); |
||
204 | |||
205 | /* Check for failure of the Region Setup */ |
||
206 | |||
207 | if (ACPI_FAILURE(status)) { |
||
208 | ACPI_EXCEPTION((AE_INFO, status, |
||
209 | "During region initialization: [%s]", |
||
210 | acpi_ut_get_region_name(region_obj-> |
||
211 | region. |
||
212 | space_id))); |
||
213 | return_ACPI_STATUS(status); |
||
214 | } |
||
215 | |||
216 | /* Region initialization may have been completed by region_setup */ |
||
217 | |||
218 | if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) { |
||
219 | region_obj->region.flags |= AOPOBJ_SETUP_COMPLETE; |
||
220 | |||
221 | /* |
||
222 | * Save the returned context for use in all accesses to |
||
223 | * the handler for this particular region |
||
224 | */ |
||
225 | if (!(region_obj2->extra.region_context)) { |
||
226 | region_obj2->extra.region_context = |
||
227 | region_context; |
||
228 | } |
||
229 | } |
||
230 | } |
||
231 | |||
232 | /* We have everything we need, we can invoke the address space handler */ |
||
233 | |||
234 | handler = handler_desc->address_space.handler; |
||
235 | address = (region_obj->region.address + region_offset); |
||
236 | |||
237 | /* |
||
238 | * Special handling for generic_serial_bus and general_purpose_io: |
||
239 | * There are three extra parameters that must be passed to the |
||
240 | * handler via the context: |
||
241 | * 1) Connection buffer, a resource template from Connection() op |
||
242 | * 2) Length of the above buffer |
||
243 | * 3) Actual access length from the access_as() op |
||
244 | * |
||
245 | * In addition, for general_purpose_io, the Address and bit_width fields |
||
246 | * are defined as follows: |
||
247 | * 1) Address is the pin number index of the field (bit offset from |
||
248 | * the previous Connection) |
||
249 | * 2) bit_width is the actual bit length of the field (number of pins) |
||
250 | */ |
||
251 | if ((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) && |
||
252 | context && field_obj) { |
||
253 | |||
254 | /* Get the Connection (resource_template) buffer */ |
||
255 | |||
256 | context->connection = field_obj->field.resource_buffer; |
||
257 | context->length = field_obj->field.resource_length; |
||
258 | context->access_length = field_obj->field.access_length; |
||
259 | } |
||
260 | if ((region_obj->region.space_id == ACPI_ADR_SPACE_GPIO) && |
||
261 | context && field_obj) { |
||
262 | |||
263 | /* Get the Connection (resource_template) buffer */ |
||
264 | |||
265 | context->connection = field_obj->field.resource_buffer; |
||
266 | context->length = field_obj->field.resource_length; |
||
267 | context->access_length = field_obj->field.access_length; |
||
268 | address = field_obj->field.pin_number_index; |
||
269 | bit_width = field_obj->field.bit_length; |
||
270 | } |
||
271 | |||
272 | ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, |
||
273 | "Handler %p (@%p) Address %8.8X%8.8X [%s]\n", |
||
274 | ®ion_obj->region.handler->address_space, handler, |
||
275 | ACPI_FORMAT_UINT64(address), |
||
276 | acpi_ut_get_region_name(region_obj->region. |
||
277 | space_id))); |
||
278 | |||
279 | if (!(handler_desc->address_space.handler_flags & |
||
280 | ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { |
||
281 | /* |
||
282 | * For handlers other than the default (supplied) handlers, we must |
||
283 | * exit the interpreter because the handler *might* block -- we don't |
||
284 | * know what it will do, so we can't hold the lock on the intepreter. |
||
285 | */ |
||
286 | acpi_ex_exit_interpreter(); |
||
287 | } |
||
288 | |||
289 | /* Call the handler */ |
||
290 | |||
291 | status = handler(function, address, bit_width, value, context, |
||
292 | region_obj2->extra.region_context); |
||
293 | |||
294 | if (ACPI_FAILURE(status)) { |
||
295 | ACPI_EXCEPTION((AE_INFO, status, "Returned by Handler for [%s]", |
||
296 | acpi_ut_get_region_name(region_obj->region. |
||
297 | space_id))); |
||
298 | } |
||
299 | |||
300 | if (!(handler_desc->address_space.handler_flags & |
||
301 | ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { |
||
302 | /* |
||
303 | * We just returned from a non-default handler, we must re-enter the |
||
304 | * interpreter |
||
305 | */ |
||
306 | acpi_ex_enter_interpreter(); |
||
307 | } |
||
308 | |||
309 | return_ACPI_STATUS(status); |
||
310 | } |
||
311 | |||
312 | /******************************************************************************* |
||
313 | * |
||
314 | * FUNCTION: acpi_ev_detach_region |
||
315 | * |
||
316 | * PARAMETERS: region_obj - Region Object |
||
317 | * acpi_ns_is_locked - Namespace Region Already Locked? |
||
318 | * |
||
319 | * RETURN: None |
||
320 | * |
||
321 | * DESCRIPTION: Break the association between the handler and the region |
||
322 | * this is a two way association. |
||
323 | * |
||
324 | ******************************************************************************/ |
||
325 | |||
326 | void |
||
327 | acpi_ev_detach_region(union acpi_operand_object *region_obj, |
||
328 | u8 acpi_ns_is_locked) |
||
329 | { |
||
330 | union acpi_operand_object *handler_obj; |
||
331 | union acpi_operand_object *obj_desc; |
||
332 | union acpi_operand_object *start_desc; |
||
333 | union acpi_operand_object **last_obj_ptr; |
||
334 | acpi_adr_space_setup region_setup; |
||
335 | void **region_context; |
||
336 | union acpi_operand_object *region_obj2; |
||
337 | acpi_status status; |
||
338 | |||
339 | ACPI_FUNCTION_TRACE(ev_detach_region); |
||
340 | |||
341 | region_obj2 = acpi_ns_get_secondary_object(region_obj); |
||
342 | if (!region_obj2) { |
||
343 | return_VOID; |
||
344 | } |
||
345 | region_context = ®ion_obj2->extra.region_context; |
||
346 | |||
347 | /* Get the address handler from the region object */ |
||
348 | |||
349 | handler_obj = region_obj->region.handler; |
||
350 | if (!handler_obj) { |
||
351 | |||
352 | /* This region has no handler, all done */ |
||
353 | |||
354 | return_VOID; |
||
355 | } |
||
356 | |||
357 | /* Find this region in the handler's list */ |
||
358 | |||
359 | obj_desc = handler_obj->address_space.region_list; |
||
360 | start_desc = obj_desc; |
||
361 | last_obj_ptr = &handler_obj->address_space.region_list; |
||
362 | |||
363 | while (obj_desc) { |
||
364 | |||
365 | /* Is this the correct Region? */ |
||
366 | |||
367 | if (obj_desc == region_obj) { |
||
368 | ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, |
||
369 | "Removing Region %p from address handler %p\n", |
||
370 | region_obj, handler_obj)); |
||
371 | |||
372 | /* This is it, remove it from the handler's list */ |
||
373 | |||
374 | *last_obj_ptr = obj_desc->region.next; |
||
375 | obj_desc->region.next = NULL; /* Must clear field */ |
||
376 | |||
377 | if (acpi_ns_is_locked) { |
||
378 | status = |
||
379 | acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
||
380 | if (ACPI_FAILURE(status)) { |
||
381 | return_VOID; |
||
382 | } |
||
383 | } |
||
384 | |||
385 | /* Now stop region accesses by executing the _REG method */ |
||
386 | |||
387 | status = |
||
388 | acpi_ev_execute_reg_method(region_obj, |
||
389 | ACPI_REG_DISCONNECT); |
||
390 | if (ACPI_FAILURE(status)) { |
||
391 | ACPI_EXCEPTION((AE_INFO, status, |
||
392 | "from region _REG, [%s]", |
||
393 | acpi_ut_get_region_name |
||
394 | (region_obj->region.space_id))); |
||
395 | } |
||
396 | |||
397 | if (acpi_ns_is_locked) { |
||
398 | status = |
||
399 | acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
||
400 | if (ACPI_FAILURE(status)) { |
||
401 | return_VOID; |
||
402 | } |
||
403 | } |
||
404 | |||
405 | /* |
||
406 | * If the region has been activated, call the setup handler with |
||
407 | * the deactivate notification |
||
408 | */ |
||
409 | if (region_obj->region.flags & AOPOBJ_SETUP_COMPLETE) { |
||
410 | region_setup = handler_obj->address_space.setup; |
||
411 | status = |
||
412 | region_setup(region_obj, |
||
413 | ACPI_REGION_DEACTIVATE, |
||
414 | handler_obj->address_space. |
||
415 | context, region_context); |
||
416 | |||
417 | /* |
||
418 | * region_context should have been released by the deactivate |
||
419 | * operation. We don't need access to it anymore here. |
||
420 | */ |
||
421 | if (region_context) { |
||
422 | *region_context = NULL; |
||
423 | } |
||
424 | |||
425 | /* Init routine may fail, Just ignore errors */ |
||
426 | |||
427 | if (ACPI_FAILURE(status)) { |
||
428 | ACPI_EXCEPTION((AE_INFO, status, |
||
429 | "from region handler - deactivate, [%s]", |
||
430 | acpi_ut_get_region_name |
||
431 | (region_obj->region. |
||
432 | space_id))); |
||
433 | } |
||
434 | |||
435 | region_obj->region.flags &= |
||
436 | ~(AOPOBJ_SETUP_COMPLETE); |
||
437 | } |
||
438 | |||
439 | /* |
||
440 | * Remove handler reference in the region |
||
441 | * |
||
442 | * NOTE: this doesn't mean that the region goes away, the region |
||
443 | * is just inaccessible as indicated to the _REG method |
||
444 | * |
||
445 | * If the region is on the handler's list, this must be the |
||
446 | * region's handler |
||
447 | */ |
||
448 | region_obj->region.handler = NULL; |
||
449 | acpi_ut_remove_reference(handler_obj); |
||
450 | |||
451 | return_VOID; |
||
452 | } |
||
453 | |||
454 | /* Walk the linked list of handlers */ |
||
455 | |||
456 | last_obj_ptr = &obj_desc->region.next; |
||
457 | obj_desc = obj_desc->region.next; |
||
458 | |||
459 | /* Prevent infinite loop if list is corrupted */ |
||
460 | |||
461 | if (obj_desc == start_desc) { |
||
462 | ACPI_ERROR((AE_INFO, |
||
463 | "Circular handler list in region object %p", |
||
464 | region_obj)); |
||
465 | return_VOID; |
||
466 | } |
||
467 | } |
||
468 | |||
469 | /* If we get here, the region was not in the handler's region list */ |
||
470 | |||
471 | ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, |
||
472 | "Cannot remove region %p from address handler %p\n", |
||
473 | region_obj, handler_obj)); |
||
474 | |||
475 | return_VOID; |
||
476 | } |
||
477 | |||
478 | /******************************************************************************* |
||
479 | * |
||
480 | * FUNCTION: acpi_ev_attach_region |
||
481 | * |
||
482 | * PARAMETERS: handler_obj - Handler Object |
||
483 | * region_obj - Region Object |
||
484 | * acpi_ns_is_locked - Namespace Region Already Locked? |
||
485 | * |
||
486 | * RETURN: None |
||
487 | * |
||
488 | * DESCRIPTION: Create the association between the handler and the region |
||
489 | * this is a two way association. |
||
490 | * |
||
491 | ******************************************************************************/ |
||
492 | |||
493 | acpi_status |
||
494 | acpi_ev_attach_region(union acpi_operand_object *handler_obj, |
||
495 | union acpi_operand_object *region_obj, |
||
496 | u8 acpi_ns_is_locked) |
||
497 | { |
||
498 | |||
499 | ACPI_FUNCTION_TRACE(ev_attach_region); |
||
500 | |||
501 | ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, |
||
502 | "Adding Region [%4.4s] %p to address handler %p [%s]\n", |
||
503 | acpi_ut_get_node_name(region_obj->region.node), |
||
504 | region_obj, handler_obj, |
||
505 | acpi_ut_get_region_name(region_obj->region. |
||
506 | space_id))); |
||
507 | |||
508 | /* Link this region to the front of the handler's list */ |
||
509 | |||
510 | region_obj->region.next = handler_obj->address_space.region_list; |
||
511 | handler_obj->address_space.region_list = region_obj; |
||
512 | |||
513 | /* Install the region's handler */ |
||
514 | |||
515 | if (region_obj->region.handler) { |
||
516 | return_ACPI_STATUS(AE_ALREADY_EXISTS); |
||
517 | } |
||
518 | |||
519 | region_obj->region.handler = handler_obj; |
||
520 | acpi_ut_add_reference(handler_obj); |
||
521 | |||
522 | return_ACPI_STATUS(AE_OK); |
||
523 | } |
||
524 | |||
525 | /******************************************************************************* |
||
526 | * |
||
527 | * FUNCTION: acpi_ev_execute_reg_method |
||
528 | * |
||
529 | * PARAMETERS: region_obj - Region object |
||
530 | * function - Passed to _REG: On (1) or Off (0) |
||
531 | * |
||
532 | * RETURN: Status |
||
533 | * |
||
534 | * DESCRIPTION: Execute _REG method for a region |
||
535 | * |
||
536 | ******************************************************************************/ |
||
537 | |||
538 | acpi_status |
||
539 | acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) |
||
540 | { |
||
541 | struct acpi_evaluate_info *info; |
||
542 | union acpi_operand_object *args[3]; |
||
543 | union acpi_operand_object *region_obj2; |
||
544 | acpi_status status; |
||
545 | |||
546 | ACPI_FUNCTION_TRACE(ev_execute_reg_method); |
||
547 | |||
548 | region_obj2 = acpi_ns_get_secondary_object(region_obj); |
||
549 | if (!region_obj2) { |
||
550 | return_ACPI_STATUS(AE_NOT_EXIST); |
||
551 | } |
||
552 | |||
553 | if (region_obj2->extra.method_REG == NULL) { |
||
554 | return_ACPI_STATUS(AE_OK); |
||
555 | } |
||
556 | |||
557 | /* Allocate and initialize the evaluation information block */ |
||
558 | |||
559 | info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); |
||
560 | if (!info) { |
||
561 | return_ACPI_STATUS(AE_NO_MEMORY); |
||
562 | } |
||
563 | |||
564 | info->prefix_node = region_obj2->extra.method_REG; |
||
565 | info->relative_pathname = NULL; |
||
566 | info->parameters = args; |
||
567 | info->flags = ACPI_IGNORE_RETURN_VALUE; |
||
568 | |||
569 | /* |
||
570 | * The _REG method has two arguments: |
||
571 | * |
||
572 | * arg0 - Integer: |
||
573 | * Operation region space ID Same value as region_obj->Region.space_id |
||
574 | * |
||
575 | * arg1 - Integer: |
||
576 | * connection status 1 for connecting the handler, 0 for disconnecting |
||
577 | * the handler (Passed as a parameter) |
||
578 | */ |
||
579 | args[0] = |
||
580 | acpi_ut_create_integer_object((u64)region_obj->region.space_id); |
||
581 | if (!args[0]) { |
||
582 | status = AE_NO_MEMORY; |
||
583 | goto cleanup1; |
||
584 | } |
||
585 | |||
586 | args[1] = acpi_ut_create_integer_object((u64)function); |
||
587 | if (!args[1]) { |
||
588 | status = AE_NO_MEMORY; |
||
589 | goto cleanup2; |
||
590 | } |
||
591 | |||
592 | args[2] = NULL; /* Terminate list */ |
||
593 | |||
594 | /* Execute the method, no return value */ |
||
595 | |||
596 | ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname |
||
597 | (ACPI_TYPE_METHOD, info->prefix_node, NULL)); |
||
598 | |||
599 | status = acpi_ns_evaluate(info); |
||
600 | acpi_ut_remove_reference(args[1]); |
||
601 | |||
602 | cleanup2: |
||
603 | acpi_ut_remove_reference(args[0]); |
||
604 | |||
605 | cleanup1: |
||
606 | ACPI_FREE(info); |
||
607 | return_ACPI_STATUS(status); |
||
608 | } |
||
609 | |||
610 | /******************************************************************************* |
||
611 | * |
||
612 | * FUNCTION: acpi_ev_execute_reg_methods |
||
613 | * |
||
614 | * PARAMETERS: node - Namespace node for the device |
||
615 | * space_id - The address space ID |
||
616 | * |
||
617 | * RETURN: Status |
||
618 | * |
||
619 | * DESCRIPTION: Run all _REG methods for the input Space ID; |
||
620 | * Note: assumes namespace is locked, or system init time. |
||
621 | * |
||
622 | ******************************************************************************/ |
||
623 | |||
624 | acpi_status |
||
625 | acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, |
||
626 | acpi_adr_space_type space_id) |
||
627 | { |
||
628 | acpi_status status; |
||
629 | struct acpi_reg_walk_info info; |
||
630 | |||
631 | ACPI_FUNCTION_TRACE(ev_execute_reg_methods); |
||
632 | |||
633 | info.space_id = space_id; |
||
634 | info.reg_run_count = 0; |
||
635 | |||
636 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_NAMES, |
||
637 | " Running _REG methods for SpaceId %s\n", |
||
638 | acpi_ut_get_region_name(info.space_id))); |
||
639 | |||
640 | /* |
||
641 | * Run all _REG methods for all Operation Regions for this space ID. This |
||
642 | * is a separate walk in order to handle any interdependencies between |
||
643 | * regions and _REG methods. (i.e. handlers must be installed for all |
||
644 | * regions of this Space ID before we can run any _REG methods) |
||
645 | */ |
||
646 | status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX, |
||
647 | ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run, |
||
648 | NULL, &info, NULL); |
||
649 | |||
650 | /* Special case for EC: handle "orphan" _REG methods with no region */ |
||
651 | |||
652 | if (space_id == ACPI_ADR_SPACE_EC) { |
||
653 | acpi_ev_orphan_ec_reg_method(node); |
||
654 | } |
||
655 | |||
656 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_NAMES, |
||
657 | " Executed %u _REG methods for SpaceId %s\n", |
||
658 | info.reg_run_count, |
||
659 | acpi_ut_get_region_name(info.space_id))); |
||
660 | |||
661 | return_ACPI_STATUS(status); |
||
662 | } |
||
663 | |||
664 | /******************************************************************************* |
||
665 | * |
||
666 | * FUNCTION: acpi_ev_reg_run |
||
667 | * |
||
668 | * PARAMETERS: walk_namespace callback |
||
669 | * |
||
670 | * DESCRIPTION: Run _REG method for region objects of the requested spaceID |
||
671 | * |
||
672 | ******************************************************************************/ |
||
673 | |||
674 | static acpi_status |
||
675 | acpi_ev_reg_run(acpi_handle obj_handle, |
||
676 | u32 level, void *context, void **return_value) |
||
677 | { |
||
678 | union acpi_operand_object *obj_desc; |
||
679 | struct acpi_namespace_node *node; |
||
680 | acpi_status status; |
||
681 | struct acpi_reg_walk_info *info; |
||
682 | |||
683 | info = ACPI_CAST_PTR(struct acpi_reg_walk_info, context); |
||
684 | |||
685 | /* Convert and validate the device handle */ |
||
686 | |||
687 | node = acpi_ns_validate_handle(obj_handle); |
||
688 | if (!node) { |
||
689 | return (AE_BAD_PARAMETER); |
||
690 | } |
||
691 | |||
692 | /* |
||
693 | * We only care about regions.and objects that are allowed to have address |
||
694 | * space handlers |
||
695 | */ |
||
696 | if ((node->type != ACPI_TYPE_REGION) && (node != acpi_gbl_root_node)) { |
||
697 | return (AE_OK); |
||
698 | } |
||
699 | |||
700 | /* Check for an existing internal object */ |
||
701 | |||
702 | obj_desc = acpi_ns_get_attached_object(node); |
||
703 | if (!obj_desc) { |
||
704 | |||
705 | /* No object, just exit */ |
||
706 | |||
707 | return (AE_OK); |
||
708 | } |
||
709 | |||
710 | /* Object is a Region */ |
||
711 | |||
712 | if (obj_desc->region.space_id != info->space_id) { |
||
713 | |||
714 | /* This region is for a different address space, just ignore it */ |
||
715 | |||
716 | return (AE_OK); |
||
717 | } |
||
718 | |||
719 | info->reg_run_count++; |
||
720 | status = acpi_ev_execute_reg_method(obj_desc, ACPI_REG_CONNECT); |
||
721 | return (status); |
||
722 | } |
||
723 | |||
724 | /******************************************************************************* |
||
725 | * |
||
726 | * FUNCTION: acpi_ev_orphan_ec_reg_method |
||
727 | * |
||
728 | * PARAMETERS: ec_device_node - Namespace node for an EC device |
||
729 | * |
||
730 | * RETURN: None |
||
731 | * |
||
732 | * DESCRIPTION: Execute an "orphan" _REG method that appears under the EC |
||
733 | * device. This is a _REG method that has no corresponding region |
||
734 | * within the EC device scope. The orphan _REG method appears to |
||
735 | * have been enabled by the description of the ECDT in the ACPI |
||
736 | * specification: "The availability of the region space can be |
||
737 | * detected by providing a _REG method object underneath the |
||
738 | * Embedded Controller device." |
||
739 | * |
||
740 | * To quickly access the EC device, we use the ec_device_node used |
||
741 | * during EC handler installation. Otherwise, we would need to |
||
742 | * perform a time consuming namespace walk, executing _HID |
||
743 | * methods to find the EC device. |
||
744 | * |
||
745 | * MUTEX: Assumes the namespace is locked |
||
746 | * |
||
747 | ******************************************************************************/ |
||
748 | |||
749 | static void |
||
750 | acpi_ev_orphan_ec_reg_method(struct acpi_namespace_node *ec_device_node) |
||
751 | { |
||
752 | acpi_handle reg_method; |
||
753 | struct acpi_namespace_node *next_node; |
||
754 | acpi_status status; |
||
755 | struct acpi_object_list args; |
||
756 | union acpi_object objects[2]; |
||
757 | |||
758 | ACPI_FUNCTION_TRACE(ev_orphan_ec_reg_method); |
||
759 | |||
760 | if (!ec_device_node) { |
||
761 | return_VOID; |
||
762 | } |
||
763 | |||
764 | /* Namespace is currently locked, must release */ |
||
765 | |||
766 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
||
767 | |||
768 | /* Get a handle to a _REG method immediately under the EC device */ |
||
769 | |||
770 | status = acpi_get_handle(ec_device_node, METHOD_NAME__REG, ®_method); |
||
771 | if (ACPI_FAILURE(status)) { |
||
772 | goto exit; /* There is no _REG method present */ |
||
773 | } |
||
774 | |||
775 | /* |
||
776 | * Execute the _REG method only if there is no Operation Region in |
||
777 | * this scope with the Embedded Controller space ID. Otherwise, it |
||
778 | * will already have been executed. Note, this allows for Regions |
||
779 | * with other space IDs to be present; but the code below will then |
||
780 | * execute the _REG method with the embedded_control space_ID argument. |
||
781 | */ |
||
782 | next_node = acpi_ns_get_next_node(ec_device_node, NULL); |
||
783 | while (next_node) { |
||
784 | if ((next_node->type == ACPI_TYPE_REGION) && |
||
785 | (next_node->object) && |
||
786 | (next_node->object->region.space_id == ACPI_ADR_SPACE_EC)) { |
||
787 | goto exit; /* Do not execute the _REG */ |
||
788 | } |
||
789 | |||
790 | next_node = acpi_ns_get_next_node(ec_device_node, next_node); |
||
791 | } |
||
792 | |||
793 | /* Evaluate the _REG(embedded_control,Connect) method */ |
||
794 | |||
795 | args.count = 2; |
||
796 | args.pointer = objects; |
||
797 | objects[0].type = ACPI_TYPE_INTEGER; |
||
798 | objects[0].integer.value = ACPI_ADR_SPACE_EC; |
||
799 | objects[1].type = ACPI_TYPE_INTEGER; |
||
800 | objects[1].integer.value = ACPI_REG_CONNECT; |
||
801 | |||
802 | status = acpi_evaluate_object(reg_method, NULL, &args, NULL); |
||
803 | |||
804 | exit: |
||
805 | /* We ignore all errors from above, don't care */ |
||
806 | |||
807 | status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
||
808 | return_VOID; |
||
809 | }> |