1 | /******************************************************************************* |
2 | * |
3 | * Module Name: nsaccess - Top-level functions for accessing ACPI namespace |
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 "amlcode.h" |
47 | #include "acnamesp.h" |
48 | #include "acdispat.h" |
49 | |
50 | |
51 | #define _COMPONENT ACPI_NAMESPACE |
52 | ACPI_MODULE_NAME ("nsaccess" ) |
53 | |
54 | |
55 | /******************************************************************************* |
56 | * |
57 | * FUNCTION: AcpiNsRootInitialize |
58 | * |
59 | * PARAMETERS: None |
60 | * |
61 | * RETURN: Status |
62 | * |
63 | * DESCRIPTION: Allocate and initialize the default root named objects |
64 | * |
65 | * MUTEX: Locks namespace for entire execution |
66 | * |
67 | ******************************************************************************/ |
68 | |
69 | ACPI_STATUS |
70 | AcpiNsRootInitialize ( |
71 | void) |
72 | { |
73 | ACPI_STATUS Status; |
74 | const ACPI_PREDEFINED_NAMES *InitVal = NULL; |
75 | ACPI_NAMESPACE_NODE *NewNode; |
76 | ACPI_OPERAND_OBJECT *ObjDesc; |
77 | ACPI_STRING Val = NULL; |
78 | |
79 | |
80 | ACPI_FUNCTION_TRACE (NsRootInitialize); |
81 | |
82 | |
83 | Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); |
84 | if (ACPI_FAILURE (Status)) |
85 | { |
86 | return_ACPI_STATUS (Status); |
87 | } |
88 | |
89 | /* |
90 | * The global root ptr is initially NULL, so a non-NULL value indicates |
91 | * that AcpiNsRootInitialize() has already been called; just return. |
92 | */ |
93 | if (AcpiGbl_RootNode) |
94 | { |
95 | Status = AE_OK; |
96 | goto UnlockAndExit; |
97 | } |
98 | |
99 | /* |
100 | * Tell the rest of the subsystem that the root is initialized |
101 | * (This is OK because the namespace is locked) |
102 | */ |
103 | AcpiGbl_RootNode = &AcpiGbl_RootNodeStruct; |
104 | |
105 | /* Enter the pre-defined names in the name table */ |
106 | |
107 | ACPI_DEBUG_PRINT ((ACPI_DB_INFO, |
108 | "Entering predefined entries into namespace\n" )); |
109 | |
110 | for (InitVal = AcpiGbl_PreDefinedNames; InitVal->Name; InitVal++) |
111 | { |
112 | /* _OSI is optional for now, will be permanent later */ |
113 | |
114 | if (!strcmp (InitVal->Name, "_OSI" ) && !AcpiGbl_CreateOsiMethod) |
115 | { |
116 | continue; |
117 | } |
118 | |
119 | Status = AcpiNsLookup (NULL, ACPI_CAST_PTR (char, InitVal->Name), |
120 | InitVal->Type, ACPI_IMODE_LOAD_PASS2, ACPI_NS_NO_UPSEARCH, |
121 | NULL, &NewNode); |
122 | if (ACPI_FAILURE (Status)) |
123 | { |
124 | ACPI_EXCEPTION ((AE_INFO, Status, |
125 | "Could not create predefined name %s" , |
126 | InitVal->Name)); |
127 | continue; |
128 | } |
129 | |
130 | /* |
131 | * Name entered successfully. If entry in PreDefinedNames[] specifies |
132 | * an initial value, create the initial value. |
133 | */ |
134 | if (InitVal->Val) |
135 | { |
136 | Status = AcpiOsPredefinedOverride (InitVal, &Val); |
137 | if (ACPI_FAILURE (Status)) |
138 | { |
139 | ACPI_ERROR ((AE_INFO, |
140 | "Could not override predefined %s" , |
141 | InitVal->Name)); |
142 | } |
143 | |
144 | if (!Val) |
145 | { |
146 | Val = __UNCONST(InitVal->Val); |
147 | } |
148 | |
149 | /* |
150 | * Entry requests an initial value, allocate a |
151 | * descriptor for it. |
152 | */ |
153 | ObjDesc = AcpiUtCreateInternalObject (InitVal->Type); |
154 | if (!ObjDesc) |
155 | { |
156 | Status = AE_NO_MEMORY; |
157 | goto UnlockAndExit; |
158 | } |
159 | |
160 | /* |
161 | * Convert value string from table entry to |
162 | * internal representation. Only types actually |
163 | * used for initial values are implemented here. |
164 | */ |
165 | switch (InitVal->Type) |
166 | { |
167 | case ACPI_TYPE_METHOD: |
168 | |
169 | ObjDesc->Method.ParamCount = (UINT8) ACPI_TO_INTEGER (Val); |
170 | ObjDesc->Common.Flags |= AOPOBJ_DATA_VALID; |
171 | |
172 | #if defined (ACPI_ASL_COMPILER) |
173 | |
174 | /* Save the parameter count for the iASL compiler */ |
175 | |
176 | NewNode->Value = ObjDesc->Method.ParamCount; |
177 | #else |
178 | /* Mark this as a very SPECIAL method */ |
179 | |
180 | ObjDesc->Method.InfoFlags = ACPI_METHOD_INTERNAL_ONLY; |
181 | ObjDesc->Method.Dispatch.Implementation = AcpiUtOsiImplementation; |
182 | #endif |
183 | break; |
184 | |
185 | case ACPI_TYPE_INTEGER: |
186 | |
187 | ObjDesc->Integer.Value = ACPI_TO_INTEGER (Val); |
188 | break; |
189 | |
190 | case ACPI_TYPE_STRING: |
191 | |
192 | /* Build an object around the static string */ |
193 | |
194 | ObjDesc->String.Length = (UINT32) strlen (Val); |
195 | ObjDesc->String.Pointer = Val; |
196 | ObjDesc->Common.Flags |= AOPOBJ_STATIC_POINTER; |
197 | break; |
198 | |
199 | case ACPI_TYPE_MUTEX: |
200 | |
201 | ObjDesc->Mutex.Node = NewNode; |
202 | ObjDesc->Mutex.SyncLevel = (UINT8) (ACPI_TO_INTEGER (Val) - 1); |
203 | |
204 | /* Create a mutex */ |
205 | |
206 | Status = AcpiOsCreateMutex (&ObjDesc->Mutex.OsMutex); |
207 | if (ACPI_FAILURE (Status)) |
208 | { |
209 | AcpiUtRemoveReference (ObjDesc); |
210 | goto UnlockAndExit; |
211 | } |
212 | |
213 | /* Special case for ACPI Global Lock */ |
214 | |
215 | if (strcmp (InitVal->Name, "_GL_" ) == 0) |
216 | { |
217 | AcpiGbl_GlobalLockMutex = ObjDesc; |
218 | |
219 | /* Create additional counting semaphore for global lock */ |
220 | |
221 | Status = AcpiOsCreateSemaphore ( |
222 | 1, 0, &AcpiGbl_GlobalLockSemaphore); |
223 | if (ACPI_FAILURE (Status)) |
224 | { |
225 | AcpiUtRemoveReference (ObjDesc); |
226 | goto UnlockAndExit; |
227 | } |
228 | } |
229 | break; |
230 | |
231 | default: |
232 | |
233 | ACPI_ERROR ((AE_INFO, "Unsupported initial type value 0x%X" , |
234 | InitVal->Type)); |
235 | AcpiUtRemoveReference (ObjDesc); |
236 | ObjDesc = NULL; |
237 | continue; |
238 | } |
239 | |
240 | /* Store pointer to value descriptor in the Node */ |
241 | |
242 | Status = AcpiNsAttachObject (NewNode, ObjDesc, |
243 | ObjDesc->Common.Type); |
244 | |
245 | /* Remove local reference to the object */ |
246 | |
247 | AcpiUtRemoveReference (ObjDesc); |
248 | } |
249 | } |
250 | |
251 | |
252 | UnlockAndExit: |
253 | (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); |
254 | |
255 | /* Save a handle to "_GPE", it is always present */ |
256 | |
257 | if (ACPI_SUCCESS (Status)) |
258 | { |
259 | Status = AcpiNsGetNode (NULL, "\\_GPE" , ACPI_NS_NO_UPSEARCH, |
260 | &AcpiGbl_FadtGpeDevice); |
261 | } |
262 | |
263 | return_ACPI_STATUS (Status); |
264 | } |
265 | |
266 | |
267 | /******************************************************************************* |
268 | * |
269 | * FUNCTION: AcpiNsLookup |
270 | * |
271 | * PARAMETERS: ScopeInfo - Current scope info block |
272 | * Pathname - Search pathname, in internal format |
273 | * (as represented in the AML stream) |
274 | * Type - Type associated with name |
275 | * InterpreterMode - IMODE_LOAD_PASS2 => add name if not found |
276 | * Flags - Flags describing the search restrictions |
277 | * WalkState - Current state of the walk |
278 | * ReturnNode - Where the Node is placed (if found |
279 | * or created successfully) |
280 | * |
281 | * RETURN: Status |
282 | * |
283 | * DESCRIPTION: Find or enter the passed name in the name space. |
284 | * Log an error if name not found in Exec mode. |
285 | * |
286 | * MUTEX: Assumes namespace is locked. |
287 | * |
288 | ******************************************************************************/ |
289 | |
290 | ACPI_STATUS |
291 | AcpiNsLookup ( |
292 | ACPI_GENERIC_STATE *ScopeInfo, |
293 | char *Pathname, |
294 | ACPI_OBJECT_TYPE Type, |
295 | ACPI_INTERPRETER_MODE InterpreterMode, |
296 | UINT32 Flags, |
297 | ACPI_WALK_STATE *WalkState, |
298 | ACPI_NAMESPACE_NODE **ReturnNode) |
299 | { |
300 | ACPI_STATUS Status; |
301 | char *Path = Pathname; |
302 | ACPI_NAMESPACE_NODE *PrefixNode; |
303 | ACPI_NAMESPACE_NODE *CurrentNode = NULL; |
304 | ACPI_NAMESPACE_NODE *ThisNode = NULL; |
305 | UINT32 NumSegments; |
306 | UINT32 NumCarats; |
307 | ACPI_NAME SimpleName; |
308 | ACPI_OBJECT_TYPE TypeToCheckFor; |
309 | ACPI_OBJECT_TYPE ThisSearchType; |
310 | UINT32 SearchParentFlag = ACPI_NS_SEARCH_PARENT; |
311 | UINT32 LocalFlags; |
312 | |
313 | |
314 | ACPI_FUNCTION_TRACE (NsLookup); |
315 | |
316 | |
317 | if (!ReturnNode) |
318 | { |
319 | return_ACPI_STATUS (AE_BAD_PARAMETER); |
320 | } |
321 | |
322 | LocalFlags = Flags & |
323 | ~(ACPI_NS_ERROR_IF_FOUND | ACPI_NS_OVERRIDE_IF_FOUND | |
324 | ACPI_NS_SEARCH_PARENT); |
325 | *ReturnNode = ACPI_ENTRY_NOT_FOUND; |
326 | AcpiGbl_NsLookupCount++; |
327 | |
328 | if (!AcpiGbl_RootNode) |
329 | { |
330 | return_ACPI_STATUS (AE_NO_NAMESPACE); |
331 | } |
332 | |
333 | /* Get the prefix scope. A null scope means use the root scope */ |
334 | |
335 | if ((!ScopeInfo) || |
336 | (!ScopeInfo->Scope.Node)) |
337 | { |
338 | ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, |
339 | "Null scope prefix, using root node (%p)\n" , |
340 | AcpiGbl_RootNode)); |
341 | |
342 | PrefixNode = AcpiGbl_RootNode; |
343 | } |
344 | else |
345 | { |
346 | PrefixNode = ScopeInfo->Scope.Node; |
347 | if (ACPI_GET_DESCRIPTOR_TYPE (PrefixNode) != ACPI_DESC_TYPE_NAMED) |
348 | { |
349 | ACPI_ERROR ((AE_INFO, "%p is not a namespace node [%s]" , |
350 | PrefixNode, AcpiUtGetDescriptorName (PrefixNode))); |
351 | return_ACPI_STATUS (AE_AML_INTERNAL); |
352 | } |
353 | |
354 | if (!(Flags & ACPI_NS_PREFIX_IS_SCOPE)) |
355 | { |
356 | /* |
357 | * This node might not be a actual "scope" node (such as a |
358 | * Device/Method, etc.) It could be a Package or other object |
359 | * node. Backup up the tree to find the containing scope node. |
360 | */ |
361 | while (!AcpiNsOpensScope (PrefixNode->Type) && |
362 | PrefixNode->Type != ACPI_TYPE_ANY) |
363 | { |
364 | PrefixNode = PrefixNode->Parent; |
365 | } |
366 | } |
367 | } |
368 | |
369 | /* Save type. TBD: may be no longer necessary */ |
370 | |
371 | TypeToCheckFor = Type; |
372 | |
373 | /* |
374 | * Begin examination of the actual pathname |
375 | */ |
376 | if (!Pathname) |
377 | { |
378 | /* A Null NamePath is allowed and refers to the root */ |
379 | |
380 | NumSegments = 0; |
381 | ThisNode = AcpiGbl_RootNode; |
382 | Path = __UNCONST("" ); |
383 | |
384 | ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, |
385 | "Null Pathname (Zero segments), Flags=%X\n" , Flags)); |
386 | } |
387 | else |
388 | { |
389 | /* |
390 | * Name pointer is valid (and must be in internal name format) |
391 | * |
392 | * Check for scope prefixes: |
393 | * |
394 | * As represented in the AML stream, a namepath consists of an |
395 | * optional scope prefix followed by a name segment part. |
396 | * |
397 | * If present, the scope prefix is either a Root Prefix (in |
398 | * which case the name is fully qualified), or one or more |
399 | * Parent Prefixes (in which case the name's scope is relative |
400 | * to the current scope). |
401 | */ |
402 | if (*Path == (UINT8) AML_ROOT_PREFIX) |
403 | { |
404 | /* Pathname is fully qualified, start from the root */ |
405 | |
406 | ThisNode = AcpiGbl_RootNode; |
407 | SearchParentFlag = ACPI_NS_NO_UPSEARCH; |
408 | |
409 | /* Point to name segment part */ |
410 | |
411 | Path++; |
412 | |
413 | ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, |
414 | "Path is absolute from root [%p]\n" , ThisNode)); |
415 | } |
416 | else |
417 | { |
418 | /* Pathname is relative to current scope, start there */ |
419 | |
420 | ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, |
421 | "Searching relative to prefix scope [%4.4s] (%p)\n" , |
422 | AcpiUtGetNodeName (PrefixNode), PrefixNode)); |
423 | |
424 | /* |
425 | * Handle multiple Parent Prefixes (carat) by just getting |
426 | * the parent node for each prefix instance. |
427 | */ |
428 | ThisNode = PrefixNode; |
429 | NumCarats = 0; |
430 | while (*Path == (UINT8) AML_PARENT_PREFIX) |
431 | { |
432 | /* Name is fully qualified, no search rules apply */ |
433 | |
434 | SearchParentFlag = ACPI_NS_NO_UPSEARCH; |
435 | |
436 | /* |
437 | * Point past this prefix to the name segment |
438 | * part or the next Parent Prefix |
439 | */ |
440 | Path++; |
441 | |
442 | /* Backup to the parent node */ |
443 | |
444 | NumCarats++; |
445 | ThisNode = ThisNode->Parent; |
446 | if (!ThisNode) |
447 | { |
448 | /* Current scope has no parent scope */ |
449 | |
450 | ACPI_ERROR ((AE_INFO, |
451 | "%s: Path has too many parent prefixes (^) " |
452 | "- reached beyond root node" , Pathname)); |
453 | return_ACPI_STATUS (AE_NOT_FOUND); |
454 | } |
455 | } |
456 | |
457 | if (SearchParentFlag == ACPI_NS_NO_UPSEARCH) |
458 | { |
459 | ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, |
460 | "Search scope is [%4.4s], path has %u carat(s)\n" , |
461 | AcpiUtGetNodeName (ThisNode), NumCarats)); |
462 | } |
463 | } |
464 | |
465 | /* |
466 | * Determine the number of ACPI name segments in this pathname. |
467 | * |
468 | * The segment part consists of either: |
469 | * - A Null name segment (0) |
470 | * - A DualNamePrefix followed by two 4-byte name segments |
471 | * - A MultiNamePrefix followed by a byte indicating the |
472 | * number of segments and the segments themselves. |
473 | * - A single 4-byte name segment |
474 | * |
475 | * Examine the name prefix opcode, if any, to determine the number of |
476 | * segments. |
477 | */ |
478 | switch (*Path) |
479 | { |
480 | case 0: |
481 | /* |
482 | * Null name after a root or parent prefixes. We already |
483 | * have the correct target node and there are no name segments. |
484 | */ |
485 | NumSegments = 0; |
486 | Type = ThisNode->Type; |
487 | |
488 | ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, |
489 | "Prefix-only Pathname (Zero name segments), Flags=%X\n" , |
490 | Flags)); |
491 | break; |
492 | |
493 | case AML_DUAL_NAME_PREFIX: |
494 | |
495 | /* More than one NameSeg, search rules do not apply */ |
496 | |
497 | SearchParentFlag = ACPI_NS_NO_UPSEARCH; |
498 | |
499 | /* Two segments, point to first name segment */ |
500 | |
501 | NumSegments = 2; |
502 | Path++; |
503 | |
504 | ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, |
505 | "Dual Pathname (2 segments, Flags=%X)\n" , Flags)); |
506 | break; |
507 | |
508 | case AML_MULTI_NAME_PREFIX_OP: |
509 | |
510 | /* More than one NameSeg, search rules do not apply */ |
511 | |
512 | SearchParentFlag = ACPI_NS_NO_UPSEARCH; |
513 | |
514 | /* Extract segment count, point to first name segment */ |
515 | |
516 | Path++; |
517 | NumSegments = (UINT32) (UINT8) *Path; |
518 | Path++; |
519 | |
520 | ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, |
521 | "Multi Pathname (%u Segments, Flags=%X)\n" , |
522 | NumSegments, Flags)); |
523 | break; |
524 | |
525 | default: |
526 | /* |
527 | * Not a Null name, no Dual or Multi prefix, hence there is |
528 | * only one name segment and Pathname is already pointing to it. |
529 | */ |
530 | NumSegments = 1; |
531 | |
532 | ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, |
533 | "Simple Pathname (1 segment, Flags=%X)\n" , Flags)); |
534 | break; |
535 | } |
536 | |
537 | ACPI_DEBUG_EXEC (AcpiNsPrintPathname (NumSegments, Path)); |
538 | } |
539 | |
540 | |
541 | /* |
542 | * Search namespace for each segment of the name. Loop through and |
543 | * verify (or add to the namespace) each name segment. |
544 | * |
545 | * The object type is significant only at the last name |
546 | * segment. (We don't care about the types along the path, only |
547 | * the type of the final target object.) |
548 | */ |
549 | ThisSearchType = ACPI_TYPE_ANY; |
550 | CurrentNode = ThisNode; |
551 | while (NumSegments && CurrentNode) |
552 | { |
553 | NumSegments--; |
554 | if (!NumSegments) |
555 | { |
556 | /* This is the last segment, enable typechecking */ |
557 | |
558 | ThisSearchType = Type; |
559 | |
560 | /* |
561 | * Only allow automatic parent search (search rules) if the caller |
562 | * requested it AND we have a single, non-fully-qualified NameSeg |
563 | */ |
564 | if ((SearchParentFlag != ACPI_NS_NO_UPSEARCH) && |
565 | (Flags & ACPI_NS_SEARCH_PARENT)) |
566 | { |
567 | LocalFlags |= ACPI_NS_SEARCH_PARENT; |
568 | } |
569 | |
570 | /* Set error flag according to caller */ |
571 | |
572 | if (Flags & ACPI_NS_ERROR_IF_FOUND) |
573 | { |
574 | LocalFlags |= ACPI_NS_ERROR_IF_FOUND; |
575 | } |
576 | |
577 | /* Set override flag according to caller */ |
578 | |
579 | if (Flags & ACPI_NS_OVERRIDE_IF_FOUND) |
580 | { |
581 | LocalFlags |= ACPI_NS_OVERRIDE_IF_FOUND; |
582 | } |
583 | } |
584 | |
585 | /* Extract one ACPI name from the front of the pathname */ |
586 | |
587 | ACPI_MOVE_32_TO_32 (&SimpleName, Path); |
588 | |
589 | /* Try to find the single (4 character) ACPI name */ |
590 | |
591 | Status = AcpiNsSearchAndEnter (SimpleName, WalkState, CurrentNode, |
592 | InterpreterMode, ThisSearchType, LocalFlags, &ThisNode); |
593 | if (ACPI_FAILURE (Status)) |
594 | { |
595 | if (Status == AE_NOT_FOUND) |
596 | { |
597 | /* Name not found in ACPI namespace */ |
598 | |
599 | ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, |
600 | "Name [%4.4s] not found in scope [%4.4s] %p\n" , |
601 | (char *) &SimpleName, (char *) &CurrentNode->Name, |
602 | CurrentNode)); |
603 | } |
604 | |
605 | *ReturnNode = ThisNode; |
606 | return_ACPI_STATUS (Status); |
607 | } |
608 | |
609 | /* More segments to follow? */ |
610 | |
611 | if (NumSegments > 0) |
612 | { |
613 | /* |
614 | * If we have an alias to an object that opens a scope (such as a |
615 | * device or processor), we need to dereference the alias here so |
616 | * that we can access any children of the original node (via the |
617 | * remaining segments). |
618 | */ |
619 | if (ThisNode->Type == ACPI_TYPE_LOCAL_ALIAS) |
620 | { |
621 | if (!ThisNode->Object) |
622 | { |
623 | return_ACPI_STATUS (AE_NOT_EXIST); |
624 | } |
625 | |
626 | if (AcpiNsOpensScope (((ACPI_NAMESPACE_NODE *) |
627 | ThisNode->Object)->Type)) |
628 | { |
629 | ThisNode = (ACPI_NAMESPACE_NODE *) ThisNode->Object; |
630 | } |
631 | } |
632 | } |
633 | |
634 | /* Special handling for the last segment (NumSegments == 0) */ |
635 | |
636 | else |
637 | { |
638 | /* |
639 | * Sanity typecheck of the target object: |
640 | * |
641 | * If 1) This is the last segment (NumSegments == 0) |
642 | * 2) And we are looking for a specific type |
643 | * (Not checking for TYPE_ANY) |
644 | * 3) Which is not an alias |
645 | * 4) Which is not a local type (TYPE_SCOPE) |
646 | * 5) And the type of target object is known (not TYPE_ANY) |
647 | * 6) And target object does not match what we are looking for |
648 | * |
649 | * Then we have a type mismatch. Just warn and ignore it. |
650 | */ |
651 | if ((TypeToCheckFor != ACPI_TYPE_ANY) && |
652 | (TypeToCheckFor != ACPI_TYPE_LOCAL_ALIAS) && |
653 | (TypeToCheckFor != ACPI_TYPE_LOCAL_METHOD_ALIAS) && |
654 | (TypeToCheckFor != ACPI_TYPE_LOCAL_SCOPE) && |
655 | (ThisNode->Type != ACPI_TYPE_ANY) && |
656 | (ThisNode->Type != TypeToCheckFor)) |
657 | { |
658 | /* Complain about a type mismatch */ |
659 | |
660 | ACPI_WARNING ((AE_INFO, |
661 | "NsLookup: Type mismatch on %4.4s (%s), searching for (%s)" , |
662 | ACPI_CAST_PTR (char, &SimpleName), |
663 | AcpiUtGetTypeName (ThisNode->Type), |
664 | AcpiUtGetTypeName (TypeToCheckFor))); |
665 | } |
666 | |
667 | /* |
668 | * If this is the last name segment and we are not looking for a |
669 | * specific type, but the type of found object is known, use that |
670 | * type to (later) see if it opens a scope. |
671 | */ |
672 | if (Type == ACPI_TYPE_ANY) |
673 | { |
674 | Type = ThisNode->Type; |
675 | } |
676 | } |
677 | |
678 | /* Point to next name segment and make this node current */ |
679 | |
680 | Path += ACPI_NAME_SIZE; |
681 | CurrentNode = ThisNode; |
682 | } |
683 | |
684 | /* Always check if we need to open a new scope */ |
685 | |
686 | if (!(Flags & ACPI_NS_DONT_OPEN_SCOPE) && (WalkState)) |
687 | { |
688 | /* |
689 | * If entry is a type which opens a scope, push the new scope on the |
690 | * scope stack. |
691 | */ |
692 | if (AcpiNsOpensScope (Type)) |
693 | { |
694 | Status = AcpiDsScopeStackPush (ThisNode, Type, WalkState); |
695 | if (ACPI_FAILURE (Status)) |
696 | { |
697 | return_ACPI_STATUS (Status); |
698 | } |
699 | } |
700 | } |
701 | |
702 | *ReturnNode = ThisNode; |
703 | return_ACPI_STATUS (AE_OK); |
704 | } |
705 | |