1 | /****************************************************************************** |
2 | * |
3 | * Module Name: evregion - Operation Region support |
4 | * |
5 | *****************************************************************************/ |
6 | |
7 | /* |
8 | * Copyright (C) 2000 - 2016, 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.h" |
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 | |
54 | extern UINT8 AcpiGbl_DefaultAddressSpaces[]; |
55 | |
56 | /* Local prototypes */ |
57 | |
58 | static void |
59 | AcpiEvOrphanEcRegMethod ( |
60 | ACPI_NAMESPACE_NODE *EcDeviceNode); |
61 | |
62 | static ACPI_STATUS |
63 | AcpiEvRegRun ( |
64 | ACPI_HANDLE ObjHandle, |
65 | UINT32 Level, |
66 | void *Context, |
67 | void **ReturnValue); |
68 | |
69 | |
70 | /******************************************************************************* |
71 | * |
72 | * FUNCTION: AcpiEvInitializeOpRegions |
73 | * |
74 | * PARAMETERS: None |
75 | * |
76 | * RETURN: Status |
77 | * |
78 | * DESCRIPTION: Execute _REG methods for all Operation Regions that have |
79 | * an installed default region handler. |
80 | * |
81 | ******************************************************************************/ |
82 | |
83 | ACPI_STATUS |
84 | AcpiEvInitializeOpRegions ( |
85 | void) |
86 | { |
87 | ACPI_STATUS Status; |
88 | UINT32 i; |
89 | |
90 | |
91 | ACPI_FUNCTION_TRACE (EvInitializeOpRegions); |
92 | |
93 | |
94 | Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); |
95 | if (ACPI_FAILURE (Status)) |
96 | { |
97 | return_ACPI_STATUS (Status); |
98 | } |
99 | |
100 | /* Run the _REG methods for OpRegions in each default address space */ |
101 | |
102 | for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) |
103 | { |
104 | /* |
105 | * Make sure the installed handler is the DEFAULT handler. If not the |
106 | * default, the _REG methods will have already been run (when the |
107 | * handler was installed) |
108 | */ |
109 | if (AcpiEvHasDefaultHandler (AcpiGbl_RootNode, |
110 | AcpiGbl_DefaultAddressSpaces[i])) |
111 | { |
112 | AcpiEvExecuteRegMethods (AcpiGbl_RootNode, |
113 | AcpiGbl_DefaultAddressSpaces[i], ACPI_REG_CONNECT); |
114 | } |
115 | } |
116 | |
117 | (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); |
118 | return_ACPI_STATUS (Status); |
119 | } |
120 | |
121 | |
122 | /******************************************************************************* |
123 | * |
124 | * FUNCTION: AcpiEvAddressSpaceDispatch |
125 | * |
126 | * PARAMETERS: RegionObj - Internal region object |
127 | * FieldObj - Corresponding field. Can be NULL. |
128 | * Function - Read or Write operation |
129 | * RegionOffset - Where in the region to read or write |
130 | * BitWidth - Field width in bits (8, 16, 32, or 64) |
131 | * Value - Pointer to in or out value, must be |
132 | * a full 64-bit integer |
133 | * |
134 | * RETURN: Status |
135 | * |
136 | * DESCRIPTION: Dispatch an address space or operation region access to |
137 | * a previously installed handler. |
138 | * |
139 | * NOTE: During early initialization, we always install the default region |
140 | * handlers for Memory, I/O and PCI_Config. This ensures that these operation |
141 | * region address spaces are always available as per the ACPI specification. |
142 | * This is especially needed in order to support the execution of |
143 | * module-level AML code during loading of the ACPI tables. |
144 | * |
145 | ******************************************************************************/ |
146 | |
147 | ACPI_STATUS |
148 | AcpiEvAddressSpaceDispatch ( |
149 | ACPI_OPERAND_OBJECT *RegionObj, |
150 | ACPI_OPERAND_OBJECT *FieldObj, |
151 | UINT32 Function, |
152 | UINT32 RegionOffset, |
153 | UINT32 BitWidth, |
154 | UINT64 *Value) |
155 | { |
156 | ACPI_STATUS Status; |
157 | ACPI_ADR_SPACE_HANDLER Handler; |
158 | ACPI_ADR_SPACE_SETUP RegionSetup; |
159 | ACPI_OPERAND_OBJECT *HandlerDesc; |
160 | ACPI_OPERAND_OBJECT *RegionObj2; |
161 | void *RegionContext = NULL; |
162 | ACPI_CONNECTION_INFO *Context; |
163 | ACPI_PHYSICAL_ADDRESS Address; |
164 | |
165 | |
166 | ACPI_FUNCTION_TRACE (EvAddressSpaceDispatch); |
167 | |
168 | |
169 | RegionObj2 = AcpiNsGetSecondaryObject (RegionObj); |
170 | if (!RegionObj2) |
171 | { |
172 | return_ACPI_STATUS (AE_NOT_EXIST); |
173 | } |
174 | |
175 | /* Ensure that there is a handler associated with this region */ |
176 | |
177 | HandlerDesc = RegionObj->Region.Handler; |
178 | if (!HandlerDesc) |
179 | { |
180 | ACPI_ERROR ((AE_INFO, |
181 | "No handler for Region [%4.4s] (%p) [%s]" , |
182 | AcpiUtGetNodeName (RegionObj->Region.Node), |
183 | RegionObj, AcpiUtGetRegionName (RegionObj->Region.SpaceId))); |
184 | |
185 | return_ACPI_STATUS (AE_NOT_EXIST); |
186 | } |
187 | |
188 | Context = HandlerDesc->AddressSpace.Context; |
189 | |
190 | /* |
191 | * It may be the case that the region has never been initialized. |
192 | * Some types of regions require special init code |
193 | */ |
194 | if (!(RegionObj->Region.Flags & AOPOBJ_SETUP_COMPLETE)) |
195 | { |
196 | /* This region has not been initialized yet, do it */ |
197 | |
198 | RegionSetup = HandlerDesc->AddressSpace.Setup; |
199 | if (!RegionSetup) |
200 | { |
201 | /* No initialization routine, exit with error */ |
202 | |
203 | ACPI_ERROR ((AE_INFO, |
204 | "No init routine for region(%p) [%s]" , |
205 | RegionObj, AcpiUtGetRegionName (RegionObj->Region.SpaceId))); |
206 | return_ACPI_STATUS (AE_NOT_EXIST); |
207 | } |
208 | |
209 | /* |
210 | * We must exit the interpreter because the region setup will |
211 | * potentially execute control methods (for example, the _REG method |
212 | * for this region) |
213 | */ |
214 | AcpiExExitInterpreter (); |
215 | |
216 | Status = RegionSetup (RegionObj, ACPI_REGION_ACTIVATE, |
217 | Context, &RegionContext); |
218 | |
219 | /* Re-enter the interpreter */ |
220 | |
221 | AcpiExEnterInterpreter (); |
222 | |
223 | /* Check for failure of the Region Setup */ |
224 | |
225 | if (ACPI_FAILURE (Status)) |
226 | { |
227 | ACPI_EXCEPTION ((AE_INFO, Status, |
228 | "During region initialization: [%s]" , |
229 | AcpiUtGetRegionName (RegionObj->Region.SpaceId))); |
230 | return_ACPI_STATUS (Status); |
231 | } |
232 | |
233 | /* Region initialization may have been completed by RegionSetup */ |
234 | |
235 | if (!(RegionObj->Region.Flags & AOPOBJ_SETUP_COMPLETE)) |
236 | { |
237 | RegionObj->Region.Flags |= AOPOBJ_SETUP_COMPLETE; |
238 | |
239 | /* |
240 | * Save the returned context for use in all accesses to |
241 | * the handler for this particular region |
242 | */ |
243 | if (!(RegionObj2->Extra.RegionContext)) |
244 | { |
245 | RegionObj2->Extra.RegionContext = RegionContext; |
246 | } |
247 | } |
248 | } |
249 | |
250 | /* We have everything we need, we can invoke the address space handler */ |
251 | |
252 | Handler = HandlerDesc->AddressSpace.Handler; |
253 | Address = (RegionObj->Region.Address + RegionOffset); |
254 | |
255 | /* |
256 | * Special handling for GenericSerialBus and GeneralPurposeIo: |
257 | * There are three extra parameters that must be passed to the |
258 | * handler via the context: |
259 | * 1) Connection buffer, a resource template from Connection() op |
260 | * 2) Length of the above buffer |
261 | * 3) Actual access length from the AccessAs() op |
262 | * |
263 | * In addition, for GeneralPurposeIo, the Address and BitWidth fields |
264 | * are defined as follows: |
265 | * 1) Address is the pin number index of the field (bit offset from |
266 | * the previous Connection) |
267 | * 2) BitWidth is the actual bit length of the field (number of pins) |
268 | */ |
269 | if ((RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS) && |
270 | Context && |
271 | FieldObj) |
272 | { |
273 | /* Get the Connection (ResourceTemplate) buffer */ |
274 | |
275 | Context->Connection = FieldObj->Field.ResourceBuffer; |
276 | Context->Length = FieldObj->Field.ResourceLength; |
277 | Context->AccessLength = FieldObj->Field.AccessLength; |
278 | } |
279 | if ((RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GPIO) && |
280 | Context && |
281 | FieldObj) |
282 | { |
283 | /* Get the Connection (ResourceTemplate) buffer */ |
284 | |
285 | Context->Connection = FieldObj->Field.ResourceBuffer; |
286 | Context->Length = FieldObj->Field.ResourceLength; |
287 | Context->AccessLength = FieldObj->Field.AccessLength; |
288 | Address = FieldObj->Field.PinNumberIndex; |
289 | BitWidth = FieldObj->Field.BitLength; |
290 | } |
291 | |
292 | ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, |
293 | "Handler %p (@%p) Address %8.8X%8.8X [%s]\n" , |
294 | &RegionObj->Region.Handler->AddressSpace, Handler, |
295 | ACPI_FORMAT_UINT64 (Address), |
296 | AcpiUtGetRegionName (RegionObj->Region.SpaceId))); |
297 | |
298 | if (!(HandlerDesc->AddressSpace.HandlerFlags & |
299 | ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) |
300 | { |
301 | /* |
302 | * For handlers other than the default (supplied) handlers, we must |
303 | * exit the interpreter because the handler *might* block -- we don't |
304 | * know what it will do, so we can't hold the lock on the intepreter. |
305 | */ |
306 | AcpiExExitInterpreter(); |
307 | } |
308 | |
309 | /* Call the handler */ |
310 | |
311 | Status = Handler (Function, Address, BitWidth, Value, Context, |
312 | RegionObj2->Extra.RegionContext); |
313 | |
314 | if (ACPI_FAILURE (Status)) |
315 | { |
316 | ACPI_EXCEPTION ((AE_INFO, Status, "Returned by Handler for [%s]" , |
317 | AcpiUtGetRegionName (RegionObj->Region.SpaceId))); |
318 | } |
319 | |
320 | if (!(HandlerDesc->AddressSpace.HandlerFlags & |
321 | ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) |
322 | { |
323 | /* |
324 | * We just returned from a non-default handler, we must re-enter the |
325 | * interpreter |
326 | */ |
327 | AcpiExEnterInterpreter (); |
328 | } |
329 | |
330 | return_ACPI_STATUS (Status); |
331 | } |
332 | |
333 | |
334 | /******************************************************************************* |
335 | * |
336 | * FUNCTION: AcpiEvDetachRegion |
337 | * |
338 | * PARAMETERS: RegionObj - Region Object |
339 | * AcpiNsIsLocked - Namespace Region Already Locked? |
340 | * |
341 | * RETURN: None |
342 | * |
343 | * DESCRIPTION: Break the association between the handler and the region |
344 | * this is a two way association. |
345 | * |
346 | ******************************************************************************/ |
347 | |
348 | void |
349 | AcpiEvDetachRegion ( |
350 | ACPI_OPERAND_OBJECT *RegionObj, |
351 | BOOLEAN AcpiNsIsLocked) |
352 | { |
353 | ACPI_OPERAND_OBJECT *HandlerObj; |
354 | ACPI_OPERAND_OBJECT *ObjDesc; |
355 | ACPI_OPERAND_OBJECT *StartDesc; |
356 | ACPI_OPERAND_OBJECT **LastObjPtr; |
357 | ACPI_ADR_SPACE_SETUP RegionSetup; |
358 | void **RegionContext; |
359 | ACPI_OPERAND_OBJECT *RegionObj2; |
360 | ACPI_STATUS Status; |
361 | |
362 | |
363 | ACPI_FUNCTION_TRACE (EvDetachRegion); |
364 | |
365 | |
366 | RegionObj2 = AcpiNsGetSecondaryObject (RegionObj); |
367 | if (!RegionObj2) |
368 | { |
369 | return_VOID; |
370 | } |
371 | RegionContext = &RegionObj2->Extra.RegionContext; |
372 | |
373 | /* Get the address handler from the region object */ |
374 | |
375 | HandlerObj = RegionObj->Region.Handler; |
376 | if (!HandlerObj) |
377 | { |
378 | /* This region has no handler, all done */ |
379 | |
380 | return_VOID; |
381 | } |
382 | |
383 | /* Find this region in the handler's list */ |
384 | |
385 | ObjDesc = HandlerObj->AddressSpace.RegionList; |
386 | StartDesc = ObjDesc; |
387 | LastObjPtr = &HandlerObj->AddressSpace.RegionList; |
388 | |
389 | while (ObjDesc) |
390 | { |
391 | /* Is this the correct Region? */ |
392 | |
393 | if (ObjDesc == RegionObj) |
394 | { |
395 | ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, |
396 | "Removing Region %p from address handler %p\n" , |
397 | RegionObj, HandlerObj)); |
398 | |
399 | /* This is it, remove it from the handler's list */ |
400 | |
401 | *LastObjPtr = ObjDesc->Region.Next; |
402 | ObjDesc->Region.Next = NULL; /* Must clear field */ |
403 | |
404 | if (AcpiNsIsLocked) |
405 | { |
406 | Status = AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); |
407 | if (ACPI_FAILURE (Status)) |
408 | { |
409 | return_VOID; |
410 | } |
411 | } |
412 | |
413 | /* Now stop region accesses by executing the _REG method */ |
414 | |
415 | Status = AcpiEvExecuteRegMethod (RegionObj, ACPI_REG_DISCONNECT); |
416 | if (ACPI_FAILURE (Status)) |
417 | { |
418 | ACPI_EXCEPTION ((AE_INFO, Status, "from region _REG, [%s]" , |
419 | AcpiUtGetRegionName (RegionObj->Region.SpaceId))); |
420 | } |
421 | |
422 | if (AcpiNsIsLocked) |
423 | { |
424 | Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); |
425 | if (ACPI_FAILURE (Status)) |
426 | { |
427 | return_VOID; |
428 | } |
429 | } |
430 | |
431 | /* |
432 | * If the region has been activated, call the setup handler with |
433 | * the deactivate notification |
434 | */ |
435 | if (RegionObj->Region.Flags & AOPOBJ_SETUP_COMPLETE) |
436 | { |
437 | RegionSetup = HandlerObj->AddressSpace.Setup; |
438 | Status = RegionSetup (RegionObj, ACPI_REGION_DEACTIVATE, |
439 | HandlerObj->AddressSpace.Context, RegionContext); |
440 | |
441 | /* |
442 | * RegionContext should have been released by the deactivate |
443 | * operation. We don't need access to it anymore here. |
444 | */ |
445 | if (RegionContext) |
446 | { |
447 | *RegionContext = NULL; |
448 | } |
449 | |
450 | /* Init routine may fail, Just ignore errors */ |
451 | |
452 | if (ACPI_FAILURE (Status)) |
453 | { |
454 | ACPI_EXCEPTION ((AE_INFO, Status, |
455 | "from region handler - deactivate, [%s]" , |
456 | AcpiUtGetRegionName (RegionObj->Region.SpaceId))); |
457 | } |
458 | |
459 | RegionObj->Region.Flags &= ~(AOPOBJ_SETUP_COMPLETE); |
460 | } |
461 | |
462 | /* |
463 | * Remove handler reference in the region |
464 | * |
465 | * NOTE: this doesn't mean that the region goes away, the region |
466 | * is just inaccessible as indicated to the _REG method |
467 | * |
468 | * If the region is on the handler's list, this must be the |
469 | * region's handler |
470 | */ |
471 | RegionObj->Region.Handler = NULL; |
472 | AcpiUtRemoveReference (HandlerObj); |
473 | |
474 | return_VOID; |
475 | } |
476 | |
477 | /* Walk the linked list of handlers */ |
478 | |
479 | LastObjPtr = &ObjDesc->Region.Next; |
480 | ObjDesc = ObjDesc->Region.Next; |
481 | |
482 | /* Prevent infinite loop if list is corrupted */ |
483 | |
484 | if (ObjDesc == StartDesc) |
485 | { |
486 | ACPI_ERROR ((AE_INFO, |
487 | "Circular handler list in region object %p" , |
488 | RegionObj)); |
489 | return_VOID; |
490 | } |
491 | } |
492 | |
493 | /* If we get here, the region was not in the handler's region list */ |
494 | |
495 | ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, |
496 | "Cannot remove region %p from address handler %p\n" , |
497 | RegionObj, HandlerObj)); |
498 | |
499 | return_VOID; |
500 | } |
501 | |
502 | |
503 | /******************************************************************************* |
504 | * |
505 | * FUNCTION: AcpiEvAttachRegion |
506 | * |
507 | * PARAMETERS: HandlerObj - Handler Object |
508 | * RegionObj - Region Object |
509 | * AcpiNsIsLocked - Namespace Region Already Locked? |
510 | * |
511 | * RETURN: None |
512 | * |
513 | * DESCRIPTION: Create the association between the handler and the region |
514 | * this is a two way association. |
515 | * |
516 | ******************************************************************************/ |
517 | |
518 | ACPI_STATUS |
519 | AcpiEvAttachRegion ( |
520 | ACPI_OPERAND_OBJECT *HandlerObj, |
521 | ACPI_OPERAND_OBJECT *RegionObj, |
522 | BOOLEAN AcpiNsIsLocked) |
523 | { |
524 | |
525 | ACPI_FUNCTION_TRACE (EvAttachRegion); |
526 | |
527 | |
528 | /* Install the region's handler */ |
529 | |
530 | if (RegionObj->Region.Handler) |
531 | { |
532 | return_ACPI_STATUS (AE_ALREADY_EXISTS); |
533 | } |
534 | |
535 | ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, |
536 | "Adding Region [%4.4s] %p to address handler %p [%s]\n" , |
537 | AcpiUtGetNodeName (RegionObj->Region.Node), |
538 | RegionObj, HandlerObj, |
539 | AcpiUtGetRegionName (RegionObj->Region.SpaceId))); |
540 | |
541 | /* Link this region to the front of the handler's list */ |
542 | |
543 | RegionObj->Region.Next = HandlerObj->AddressSpace.RegionList; |
544 | HandlerObj->AddressSpace.RegionList = RegionObj; |
545 | RegionObj->Region.Handler = HandlerObj; |
546 | AcpiUtAddReference (HandlerObj); |
547 | |
548 | return_ACPI_STATUS (AE_OK); |
549 | } |
550 | |
551 | |
552 | /******************************************************************************* |
553 | * |
554 | * FUNCTION: AcpiEvExecuteRegMethod |
555 | * |
556 | * PARAMETERS: RegionObj - Region object |
557 | * Function - Passed to _REG: On (1) or Off (0) |
558 | * |
559 | * RETURN: Status |
560 | * |
561 | * DESCRIPTION: Execute _REG method for a region |
562 | * |
563 | ******************************************************************************/ |
564 | |
565 | ACPI_STATUS |
566 | AcpiEvExecuteRegMethod ( |
567 | ACPI_OPERAND_OBJECT *RegionObj, |
568 | UINT32 Function) |
569 | { |
570 | ACPI_EVALUATE_INFO *Info; |
571 | ACPI_OPERAND_OBJECT *Args[3]; |
572 | ACPI_OPERAND_OBJECT *RegionObj2; |
573 | const ACPI_NAME *RegNamePtr = ACPI_CAST_PTR (ACPI_NAME, METHOD_NAME__REG); |
574 | ACPI_NAMESPACE_NODE *MethodNode; |
575 | ACPI_NAMESPACE_NODE *Node; |
576 | ACPI_STATUS Status; |
577 | |
578 | |
579 | ACPI_FUNCTION_TRACE (EvExecuteRegMethod); |
580 | |
581 | |
582 | if (!AcpiGbl_NamespaceInitialized || |
583 | RegionObj->Region.Handler == NULL) |
584 | { |
585 | return_ACPI_STATUS (AE_OK); |
586 | } |
587 | |
588 | RegionObj2 = AcpiNsGetSecondaryObject (RegionObj); |
589 | if (!RegionObj2) |
590 | { |
591 | return_ACPI_STATUS (AE_NOT_EXIST); |
592 | } |
593 | |
594 | /* |
595 | * Find any "_REG" method associated with this region definition. |
596 | * The method should always be updated as this function may be |
597 | * invoked after a namespace change. |
598 | */ |
599 | Node = RegionObj->Region.Node->Parent; |
600 | Status = AcpiNsSearchOneScope ( |
601 | *RegNamePtr, Node, ACPI_TYPE_METHOD, &MethodNode); |
602 | if (ACPI_SUCCESS (Status)) |
603 | { |
604 | /* |
605 | * The _REG method is optional and there can be only one per |
606 | * region definition. This will be executed when the handler is |
607 | * attached or removed. |
608 | */ |
609 | RegionObj2->Extra.Method_REG = MethodNode; |
610 | } |
611 | if (RegionObj2->Extra.Method_REG == NULL) |
612 | { |
613 | return_ACPI_STATUS (AE_OK); |
614 | } |
615 | |
616 | /* _REG(DISCONNECT) should be paired with _REG(CONNECT) */ |
617 | |
618 | if ((Function == ACPI_REG_CONNECT && |
619 | RegionObj->Common.Flags & AOPOBJ_REG_CONNECTED) || |
620 | (Function == ACPI_REG_DISCONNECT && |
621 | !(RegionObj->Common.Flags & AOPOBJ_REG_CONNECTED))) |
622 | { |
623 | return_ACPI_STATUS (AE_OK); |
624 | } |
625 | |
626 | /* Allocate and initialize the evaluation information block */ |
627 | |
628 | Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); |
629 | if (!Info) |
630 | { |
631 | return_ACPI_STATUS (AE_NO_MEMORY); |
632 | } |
633 | |
634 | Info->PrefixNode = RegionObj2->Extra.Method_REG; |
635 | Info->RelativePathname = NULL; |
636 | Info->Parameters = Args; |
637 | Info->Flags = ACPI_IGNORE_RETURN_VALUE; |
638 | |
639 | /* |
640 | * The _REG method has two arguments: |
641 | * |
642 | * Arg0 - Integer: |
643 | * Operation region space ID Same value as RegionObj->Region.SpaceId |
644 | * |
645 | * Arg1 - Integer: |
646 | * connection status 1 for connecting the handler, 0 for disconnecting |
647 | * the handler (Passed as a parameter) |
648 | */ |
649 | Args[0] = AcpiUtCreateIntegerObject ((UINT64) RegionObj->Region.SpaceId); |
650 | if (!Args[0]) |
651 | { |
652 | Status = AE_NO_MEMORY; |
653 | goto Cleanup1; |
654 | } |
655 | |
656 | Args[1] = AcpiUtCreateIntegerObject ((UINT64) Function); |
657 | if (!Args[1]) |
658 | { |
659 | Status = AE_NO_MEMORY; |
660 | goto Cleanup2; |
661 | } |
662 | |
663 | Args[2] = NULL; /* Terminate list */ |
664 | |
665 | /* Execute the method, no return value */ |
666 | |
667 | ACPI_DEBUG_EXEC ( |
668 | AcpiUtDisplayInitPathname (ACPI_TYPE_METHOD, Info->PrefixNode, NULL)); |
669 | |
670 | Status = AcpiNsEvaluate (Info); |
671 | AcpiUtRemoveReference (Args[1]); |
672 | |
673 | if (ACPI_FAILURE (Status)) |
674 | { |
675 | goto Cleanup2; |
676 | } |
677 | |
678 | if (Function == ACPI_REG_CONNECT) |
679 | { |
680 | RegionObj->Common.Flags |= AOPOBJ_REG_CONNECTED; |
681 | } |
682 | else |
683 | { |
684 | RegionObj->Common.Flags &= ~AOPOBJ_REG_CONNECTED; |
685 | } |
686 | |
687 | Cleanup2: |
688 | AcpiUtRemoveReference (Args[0]); |
689 | |
690 | Cleanup1: |
691 | ACPI_FREE (Info); |
692 | return_ACPI_STATUS (Status); |
693 | } |
694 | |
695 | |
696 | /******************************************************************************* |
697 | * |
698 | * FUNCTION: AcpiEvExecuteRegMethods |
699 | * |
700 | * PARAMETERS: Node - Namespace node for the device |
701 | * SpaceId - The address space ID |
702 | * Function - Passed to _REG: On (1) or Off (0) |
703 | * |
704 | * RETURN: None |
705 | * |
706 | * DESCRIPTION: Run all _REG methods for the input Space ID; |
707 | * Note: assumes namespace is locked, or system init time. |
708 | * |
709 | ******************************************************************************/ |
710 | |
711 | void |
712 | AcpiEvExecuteRegMethods ( |
713 | ACPI_NAMESPACE_NODE *Node, |
714 | ACPI_ADR_SPACE_TYPE SpaceId, |
715 | UINT32 Function) |
716 | { |
717 | ACPI_REG_WALK_INFO Info; |
718 | |
719 | |
720 | ACPI_FUNCTION_TRACE (EvExecuteRegMethods); |
721 | |
722 | Info.SpaceId = SpaceId; |
723 | Info.Function = Function; |
724 | Info.RegRunCount = 0; |
725 | |
726 | ACPI_DEBUG_PRINT_RAW ((ACPI_DB_NAMES, |
727 | " Running _REG methods for SpaceId %s\n" , |
728 | AcpiUtGetRegionName (Info.SpaceId))); |
729 | |
730 | /* |
731 | * Run all _REG methods for all Operation Regions for this space ID. This |
732 | * is a separate walk in order to handle any interdependencies between |
733 | * regions and _REG methods. (i.e. handlers must be installed for all |
734 | * regions of this Space ID before we can run any _REG methods) |
735 | */ |
736 | (void) AcpiNsWalkNamespace (ACPI_TYPE_ANY, Node, ACPI_UINT32_MAX, |
737 | ACPI_NS_WALK_UNLOCK, AcpiEvRegRun, NULL, &Info, NULL); |
738 | |
739 | /* Special case for EC: handle "orphan" _REG methods with no region */ |
740 | |
741 | if (SpaceId == ACPI_ADR_SPACE_EC) |
742 | { |
743 | AcpiEvOrphanEcRegMethod (Node); |
744 | } |
745 | |
746 | ACPI_DEBUG_PRINT_RAW ((ACPI_DB_NAMES, |
747 | " Executed %u _REG methods for SpaceId %s\n" , |
748 | Info.RegRunCount, AcpiUtGetRegionName (Info.SpaceId))); |
749 | |
750 | return_VOID; |
751 | } |
752 | |
753 | |
754 | /******************************************************************************* |
755 | * |
756 | * FUNCTION: AcpiEvRegRun |
757 | * |
758 | * PARAMETERS: WalkNamespace callback |
759 | * |
760 | * DESCRIPTION: Run _REG method for region objects of the requested spaceID |
761 | * |
762 | ******************************************************************************/ |
763 | |
764 | static ACPI_STATUS |
765 | AcpiEvRegRun ( |
766 | ACPI_HANDLE ObjHandle, |
767 | UINT32 Level, |
768 | void *Context, |
769 | void **ReturnValue) |
770 | { |
771 | ACPI_OPERAND_OBJECT *ObjDesc; |
772 | ACPI_NAMESPACE_NODE *Node; |
773 | ACPI_STATUS Status; |
774 | ACPI_REG_WALK_INFO *Info; |
775 | |
776 | |
777 | Info = ACPI_CAST_PTR (ACPI_REG_WALK_INFO, Context); |
778 | |
779 | /* Convert and validate the device handle */ |
780 | |
781 | Node = AcpiNsValidateHandle (ObjHandle); |
782 | if (!Node) |
783 | { |
784 | return (AE_BAD_PARAMETER); |
785 | } |
786 | |
787 | /* |
788 | * We only care about regions.and objects that are allowed to have address |
789 | * space handlers |
790 | */ |
791 | if ((Node->Type != ACPI_TYPE_REGION) && |
792 | (Node != AcpiGbl_RootNode)) |
793 | { |
794 | return (AE_OK); |
795 | } |
796 | |
797 | /* Check for an existing internal object */ |
798 | |
799 | ObjDesc = AcpiNsGetAttachedObject (Node); |
800 | if (!ObjDesc) |
801 | { |
802 | /* No object, just exit */ |
803 | |
804 | return (AE_OK); |
805 | } |
806 | |
807 | /* Object is a Region */ |
808 | |
809 | if (ObjDesc->Region.SpaceId != Info->SpaceId) |
810 | { |
811 | /* This region is for a different address space, just ignore it */ |
812 | |
813 | return (AE_OK); |
814 | } |
815 | |
816 | Info->RegRunCount++; |
817 | Status = AcpiEvExecuteRegMethod (ObjDesc, Info->Function); |
818 | return (Status); |
819 | } |
820 | |
821 | |
822 | /******************************************************************************* |
823 | * |
824 | * FUNCTION: AcpiEvOrphanEcRegMethod |
825 | * |
826 | * PARAMETERS: EcDeviceNode - Namespace node for an EC device |
827 | * |
828 | * RETURN: None |
829 | * |
830 | * DESCRIPTION: Execute an "orphan" _REG method that appears under the EC |
831 | * device. This is a _REG method that has no corresponding region |
832 | * within the EC device scope. The orphan _REG method appears to |
833 | * have been enabled by the description of the ECDT in the ACPI |
834 | * specification: "The availability of the region space can be |
835 | * detected by providing a _REG method object underneath the |
836 | * Embedded Controller device." |
837 | * |
838 | * To quickly access the EC device, we use the EcDeviceNode used |
839 | * during EC handler installation. Otherwise, we would need to |
840 | * perform a time consuming namespace walk, executing _HID |
841 | * methods to find the EC device. |
842 | * |
843 | * MUTEX: Assumes the namespace is locked |
844 | * |
845 | ******************************************************************************/ |
846 | |
847 | static void |
848 | AcpiEvOrphanEcRegMethod ( |
849 | ACPI_NAMESPACE_NODE *EcDeviceNode) |
850 | { |
851 | ACPI_HANDLE RegMethod; |
852 | ACPI_NAMESPACE_NODE *NextNode; |
853 | ACPI_STATUS Status; |
854 | ACPI_OBJECT_LIST Args; |
855 | ACPI_OBJECT Objects[2]; |
856 | |
857 | |
858 | ACPI_FUNCTION_TRACE (EvOrphanEcRegMethod); |
859 | |
860 | |
861 | if (!EcDeviceNode) |
862 | { |
863 | return_VOID; |
864 | } |
865 | |
866 | /* Namespace is currently locked, must release */ |
867 | |
868 | (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); |
869 | |
870 | /* Get a handle to a _REG method immediately under the EC device */ |
871 | |
872 | Status = AcpiGetHandle (EcDeviceNode, METHOD_NAME__REG, &RegMethod); |
873 | if (ACPI_FAILURE (Status)) |
874 | { |
875 | goto Exit; /* There is no _REG method present */ |
876 | } |
877 | |
878 | /* |
879 | * Execute the _REG method only if there is no Operation Region in |
880 | * this scope with the Embedded Controller space ID. Otherwise, it |
881 | * will already have been executed. Note, this allows for Regions |
882 | * with other space IDs to be present; but the code below will then |
883 | * execute the _REG method with the EmbeddedControl SpaceID argument. |
884 | */ |
885 | NextNode = AcpiNsGetNextNode (EcDeviceNode, NULL); |
886 | while (NextNode) |
887 | { |
888 | if ((NextNode->Type == ACPI_TYPE_REGION) && |
889 | (NextNode->Object) && |
890 | (NextNode->Object->Region.SpaceId == ACPI_ADR_SPACE_EC)) |
891 | { |
892 | goto Exit; /* Do not execute the _REG */ |
893 | } |
894 | |
895 | NextNode = AcpiNsGetNextNode (EcDeviceNode, NextNode); |
896 | } |
897 | |
898 | /* Evaluate the _REG(EmbeddedControl,Connect) method */ |
899 | |
900 | Args.Count = 2; |
901 | Args.Pointer = Objects; |
902 | Objects[0].Type = ACPI_TYPE_INTEGER; |
903 | Objects[0].Integer.Value = ACPI_ADR_SPACE_EC; |
904 | Objects[1].Type = ACPI_TYPE_INTEGER; |
905 | Objects[1].Integer.Value = ACPI_REG_CONNECT; |
906 | |
907 | Status = AcpiEvaluateObject (RegMethod, NULL, &Args, NULL); |
908 | |
909 | Exit: |
910 | /* We ignore all errors from above, don't care */ |
911 | |
912 | Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); |
913 | return_VOID; |
914 | } |
915 | |