1 | /****************************************************************************** |
2 | * |
3 | * Module Name: nsxfname - Public interfaces to the ACPI subsystem |
4 | * ACPI Namespace oriented interfaces |
5 | * |
6 | *****************************************************************************/ |
7 | |
8 | /* |
9 | * Copyright (C) 2000 - 2016, Intel Corp. |
10 | * All rights reserved. |
11 | * |
12 | * Redistribution and use in source and binary forms, with or without |
13 | * modification, are permitted provided that the following conditions |
14 | * are met: |
15 | * 1. Redistributions of source code must retain the above copyright |
16 | * notice, this list of conditions, and the following disclaimer, |
17 | * without modification. |
18 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer |
19 | * substantially similar to the "NO WARRANTY" disclaimer below |
20 | * ("Disclaimer") and any redistribution must be conditioned upon |
21 | * including a substantially similar Disclaimer requirement for further |
22 | * binary redistribution. |
23 | * 3. Neither the names of the above-listed copyright holders nor the names |
24 | * of any contributors may be used to endorse or promote products derived |
25 | * from this software without specific prior written permission. |
26 | * |
27 | * Alternatively, this software may be distributed under the terms of the |
28 | * GNU General Public License ("GPL") version 2 as published by the Free |
29 | * Software Foundation. |
30 | * |
31 | * NO WARRANTY |
32 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
33 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
34 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
35 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
36 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
37 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
38 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
39 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
40 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
41 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
42 | * POSSIBILITY OF SUCH DAMAGES. |
43 | */ |
44 | |
45 | #define EXPORT_ACPI_INTERFACES |
46 | |
47 | #include "acpi.h" |
48 | #include "accommon.h" |
49 | #include "acnamesp.h" |
50 | #include "acparser.h" |
51 | #include "amlcode.h" |
52 | |
53 | |
54 | #define _COMPONENT ACPI_NAMESPACE |
55 | ACPI_MODULE_NAME ("nsxfname" ) |
56 | |
57 | /* Local prototypes */ |
58 | |
59 | static char * |
60 | AcpiNsCopyDeviceId ( |
61 | ACPI_PNP_DEVICE_ID *Dest, |
62 | ACPI_PNP_DEVICE_ID *Source, |
63 | char *StringArea); |
64 | |
65 | |
66 | /****************************************************************************** |
67 | * |
68 | * FUNCTION: AcpiGetHandle |
69 | * |
70 | * PARAMETERS: Parent - Object to search under (search scope). |
71 | * Pathname - Pointer to an asciiz string containing the |
72 | * name |
73 | * RetHandle - Where the return handle is returned |
74 | * |
75 | * RETURN: Status |
76 | * |
77 | * DESCRIPTION: This routine will search for a caller specified name in the |
78 | * name space. The caller can restrict the search region by |
79 | * specifying a non NULL parent. The parent value is itself a |
80 | * namespace handle. |
81 | * |
82 | ******************************************************************************/ |
83 | |
84 | ACPI_STATUS |
85 | AcpiGetHandle ( |
86 | ACPI_HANDLE Parent, |
87 | ACPI_CONST_STRING Pathname, |
88 | ACPI_HANDLE *RetHandle) |
89 | { |
90 | ACPI_STATUS Status; |
91 | ACPI_NAMESPACE_NODE *Node = NULL; |
92 | ACPI_NAMESPACE_NODE *PrefixNode = NULL; |
93 | ACPI_STRING UPathname = __UNCONST(Pathname); |
94 | |
95 | |
96 | ACPI_FUNCTION_ENTRY (); |
97 | |
98 | |
99 | /* Parameter Validation */ |
100 | |
101 | if (!RetHandle || !Pathname) |
102 | { |
103 | return (AE_BAD_PARAMETER); |
104 | } |
105 | |
106 | /* Convert a parent handle to a prefix node */ |
107 | |
108 | if (Parent) |
109 | { |
110 | PrefixNode = AcpiNsValidateHandle (Parent); |
111 | if (!PrefixNode) |
112 | { |
113 | return (AE_BAD_PARAMETER); |
114 | } |
115 | } |
116 | |
117 | /* |
118 | * Valid cases are: |
119 | * 1) Fully qualified pathname |
120 | * 2) Parent + Relative pathname |
121 | * |
122 | * Error for <null Parent + relative path> |
123 | */ |
124 | if (ACPI_IS_ROOT_PREFIX (Pathname[0])) |
125 | { |
126 | /* Pathname is fully qualified (starts with '\') */ |
127 | |
128 | /* Special case for root-only, since we can't search for it */ |
129 | |
130 | if (!strcmp (Pathname, ACPI_NS_ROOT_PATH)) |
131 | { |
132 | *RetHandle = ACPI_CAST_PTR (ACPI_HANDLE, AcpiGbl_RootNode); |
133 | return (AE_OK); |
134 | } |
135 | } |
136 | else if (!PrefixNode) |
137 | { |
138 | /* Relative path with null prefix is disallowed */ |
139 | |
140 | return (AE_BAD_PARAMETER); |
141 | } |
142 | |
143 | /* Find the Node and convert to a handle */ |
144 | |
145 | Status = AcpiNsGetNode (PrefixNode, UPathname, ACPI_NS_NO_UPSEARCH, &Node); |
146 | if (ACPI_SUCCESS (Status)) |
147 | { |
148 | *RetHandle = ACPI_CAST_PTR (ACPI_HANDLE, Node); |
149 | } |
150 | |
151 | return (Status); |
152 | } |
153 | |
154 | ACPI_EXPORT_SYMBOL (AcpiGetHandle) |
155 | |
156 | |
157 | /****************************************************************************** |
158 | * |
159 | * FUNCTION: AcpiGetName |
160 | * |
161 | * PARAMETERS: Handle - Handle to be converted to a pathname |
162 | * NameType - Full pathname or single segment |
163 | * Buffer - Buffer for returned path |
164 | * |
165 | * RETURN: Pointer to a string containing the fully qualified Name. |
166 | * |
167 | * DESCRIPTION: This routine returns the fully qualified name associated with |
168 | * the Handle parameter. This and the AcpiPathnameToHandle are |
169 | * complementary functions. |
170 | * |
171 | ******************************************************************************/ |
172 | |
173 | ACPI_STATUS |
174 | AcpiGetName ( |
175 | ACPI_HANDLE Handle, |
176 | UINT32 NameType, |
177 | ACPI_BUFFER *Buffer) |
178 | { |
179 | ACPI_STATUS Status; |
180 | ACPI_NAMESPACE_NODE *Node; |
181 | const char *NodeName; |
182 | |
183 | |
184 | /* Parameter validation */ |
185 | |
186 | if (NameType > ACPI_NAME_TYPE_MAX) |
187 | { |
188 | return (AE_BAD_PARAMETER); |
189 | } |
190 | |
191 | Status = AcpiUtValidateBuffer (Buffer); |
192 | if (ACPI_FAILURE (Status)) |
193 | { |
194 | return (Status); |
195 | } |
196 | |
197 | if (NameType == ACPI_FULL_PATHNAME || |
198 | NameType == ACPI_FULL_PATHNAME_NO_TRAILING) |
199 | { |
200 | /* Get the full pathname (From the namespace root) */ |
201 | |
202 | Status = AcpiNsHandleToPathname (Handle, Buffer, |
203 | NameType == ACPI_FULL_PATHNAME ? FALSE : TRUE); |
204 | return (Status); |
205 | } |
206 | |
207 | /* |
208 | * Wants the single segment ACPI name. |
209 | * Validate handle and convert to a namespace Node |
210 | */ |
211 | Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); |
212 | if (ACPI_FAILURE (Status)) |
213 | { |
214 | return (Status); |
215 | } |
216 | |
217 | Node = AcpiNsValidateHandle (Handle); |
218 | if (!Node) |
219 | { |
220 | Status = AE_BAD_PARAMETER; |
221 | goto UnlockAndExit; |
222 | } |
223 | |
224 | /* Validate/Allocate/Clear caller buffer */ |
225 | |
226 | Status = AcpiUtInitializeBuffer (Buffer, ACPI_PATH_SEGMENT_LENGTH); |
227 | if (ACPI_FAILURE (Status)) |
228 | { |
229 | goto UnlockAndExit; |
230 | } |
231 | |
232 | /* Just copy the ACPI name from the Node and zero terminate it */ |
233 | |
234 | NodeName = __UNCONST(AcpiUtGetNodeName (Node)); |
235 | ACPI_MOVE_NAME (Buffer->Pointer, NodeName); |
236 | ((char *) Buffer->Pointer) [ACPI_NAME_SIZE] = 0; |
237 | Status = AE_OK; |
238 | |
239 | |
240 | UnlockAndExit: |
241 | |
242 | (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); |
243 | return (Status); |
244 | } |
245 | |
246 | ACPI_EXPORT_SYMBOL (AcpiGetName) |
247 | |
248 | |
249 | /****************************************************************************** |
250 | * |
251 | * FUNCTION: AcpiNsCopyDeviceId |
252 | * |
253 | * PARAMETERS: Dest - Pointer to the destination PNP_DEVICE_ID |
254 | * Source - Pointer to the source PNP_DEVICE_ID |
255 | * StringArea - Pointer to where to copy the dest string |
256 | * |
257 | * RETURN: Pointer to the next string area |
258 | * |
259 | * DESCRIPTION: Copy a single PNP_DEVICE_ID, including the string data. |
260 | * |
261 | ******************************************************************************/ |
262 | |
263 | static char * |
264 | AcpiNsCopyDeviceId ( |
265 | ACPI_PNP_DEVICE_ID *Dest, |
266 | ACPI_PNP_DEVICE_ID *Source, |
267 | char *StringArea) |
268 | { |
269 | /* Create the destination PNP_DEVICE_ID */ |
270 | |
271 | Dest->String = StringArea; |
272 | Dest->Length = Source->Length; |
273 | |
274 | /* Copy actual string and return a pointer to the next string area */ |
275 | |
276 | memcpy (StringArea, Source->String, Source->Length); |
277 | return (StringArea + Source->Length); |
278 | } |
279 | |
280 | |
281 | /****************************************************************************** |
282 | * |
283 | * FUNCTION: AcpiGetObjectInfo |
284 | * |
285 | * PARAMETERS: Handle - Object Handle |
286 | * ReturnBuffer - Where the info is returned |
287 | * |
288 | * RETURN: Status |
289 | * |
290 | * DESCRIPTION: Returns information about an object as gleaned from the |
291 | * namespace node and possibly by running several standard |
292 | * control methods (Such as in the case of a device.) |
293 | * |
294 | * For Device and Processor objects, run the Device _HID, _UID, _CID, _STA, |
295 | * _CLS, _ADR, _SxW, and _SxD methods. |
296 | * |
297 | * Note: Allocates the return buffer, must be freed by the caller. |
298 | * |
299 | * Note: This interface is intended to be used during the initial device |
300 | * discovery namespace traversal. Therefore, no complex methods can be |
301 | * executed, especially those that access operation regions. Therefore, do |
302 | * not add any additional methods that could cause problems in this area. |
303 | * this was the fate of the _SUB method which was found to cause such |
304 | * problems and was removed (11/2015). |
305 | * |
306 | ******************************************************************************/ |
307 | |
308 | ACPI_STATUS |
309 | AcpiGetObjectInfo ( |
310 | ACPI_HANDLE Handle, |
311 | ACPI_DEVICE_INFO **ReturnBuffer) |
312 | { |
313 | ACPI_NAMESPACE_NODE *Node; |
314 | ACPI_DEVICE_INFO *Info; |
315 | ACPI_PNP_DEVICE_ID_LIST *CidList = NULL; |
316 | ACPI_PNP_DEVICE_ID *Hid = NULL; |
317 | ACPI_PNP_DEVICE_ID *Uid = NULL; |
318 | ACPI_PNP_DEVICE_ID *Cls = NULL; |
319 | char *NextIdString; |
320 | ACPI_OBJECT_TYPE Type; |
321 | ACPI_NAME Name; |
322 | UINT8 ParamCount= 0; |
323 | UINT16 Valid = 0; |
324 | UINT32 InfoSize; |
325 | UINT32 i; |
326 | ACPI_STATUS Status; |
327 | |
328 | |
329 | /* Parameter validation */ |
330 | |
331 | if (!Handle || !ReturnBuffer) |
332 | { |
333 | return (AE_BAD_PARAMETER); |
334 | } |
335 | |
336 | Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); |
337 | if (ACPI_FAILURE (Status)) |
338 | { |
339 | return (Status); |
340 | } |
341 | |
342 | Node = AcpiNsValidateHandle (Handle); |
343 | if (!Node) |
344 | { |
345 | (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); |
346 | return (AE_BAD_PARAMETER); |
347 | } |
348 | |
349 | /* Get the namespace node data while the namespace is locked */ |
350 | |
351 | InfoSize = sizeof (ACPI_DEVICE_INFO); |
352 | Type = Node->Type; |
353 | Name = Node->Name.Integer; |
354 | |
355 | if (Node->Type == ACPI_TYPE_METHOD) |
356 | { |
357 | ParamCount = Node->Object->Method.ParamCount; |
358 | } |
359 | |
360 | Status = AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); |
361 | if (ACPI_FAILURE (Status)) |
362 | { |
363 | return (Status); |
364 | } |
365 | |
366 | if ((Type == ACPI_TYPE_DEVICE) || |
367 | (Type == ACPI_TYPE_PROCESSOR)) |
368 | { |
369 | /* |
370 | * Get extra info for ACPI Device/Processor objects only: |
371 | * Run the Device _HID, _UID, _CLS, and _CID methods. |
372 | * |
373 | * Note: none of these methods are required, so they may or may |
374 | * not be present for this device. The Info->Valid bitfield is used |
375 | * to indicate which methods were found and run successfully. |
376 | */ |
377 | |
378 | /* Execute the Device._HID method */ |
379 | |
380 | Status = AcpiUtExecute_HID (Node, &Hid); |
381 | if (ACPI_SUCCESS (Status)) |
382 | { |
383 | InfoSize += Hid->Length; |
384 | Valid |= ACPI_VALID_HID; |
385 | } |
386 | |
387 | /* Execute the Device._UID method */ |
388 | |
389 | Status = AcpiUtExecute_UID (Node, &Uid); |
390 | if (ACPI_SUCCESS (Status)) |
391 | { |
392 | InfoSize += Uid->Length; |
393 | Valid |= ACPI_VALID_UID; |
394 | } |
395 | |
396 | /* Execute the Device._CID method */ |
397 | |
398 | Status = AcpiUtExecute_CID (Node, &CidList); |
399 | if (ACPI_SUCCESS (Status)) |
400 | { |
401 | /* Add size of CID strings and CID pointer array */ |
402 | |
403 | InfoSize += (CidList->ListSize - sizeof (ACPI_PNP_DEVICE_ID_LIST)); |
404 | Valid |= ACPI_VALID_CID; |
405 | } |
406 | |
407 | /* Execute the Device._CLS method */ |
408 | |
409 | Status = AcpiUtExecute_CLS (Node, &Cls); |
410 | if (ACPI_SUCCESS (Status)) |
411 | { |
412 | InfoSize += Cls->Length; |
413 | Valid |= ACPI_VALID_CLS; |
414 | } |
415 | } |
416 | |
417 | /* |
418 | * Now that we have the variable-length data, we can allocate the |
419 | * return buffer |
420 | */ |
421 | Info = ACPI_ALLOCATE_ZEROED (InfoSize); |
422 | if (!Info) |
423 | { |
424 | Status = AE_NO_MEMORY; |
425 | goto Cleanup; |
426 | } |
427 | |
428 | /* Get the fixed-length data */ |
429 | |
430 | if ((Type == ACPI_TYPE_DEVICE) || |
431 | (Type == ACPI_TYPE_PROCESSOR)) |
432 | { |
433 | /* |
434 | * Get extra info for ACPI Device/Processor objects only: |
435 | * Run the _STA, _ADR and, SxW, and _SxD methods. |
436 | * |
437 | * Notes: none of these methods are required, so they may or may |
438 | * not be present for this device. The Info->Valid bitfield is used |
439 | * to indicate which methods were found and run successfully. |
440 | * |
441 | * For _STA, if the method does not exist, then (as per the ACPI |
442 | * specification), the returned CurrentStatus flags will indicate |
443 | * that the device is present/functional/enabled. Otherwise, the |
444 | * CurrentStatus flags reflect the value returned from _STA. |
445 | */ |
446 | |
447 | /* Execute the Device._STA method */ |
448 | |
449 | Status = AcpiUtExecute_STA (Node, &Info->CurrentStatus); |
450 | if (ACPI_SUCCESS (Status)) |
451 | { |
452 | Valid |= ACPI_VALID_STA; |
453 | } |
454 | |
455 | /* Execute the Device._ADR method */ |
456 | |
457 | Status = AcpiUtEvaluateNumericObject (METHOD_NAME__ADR, Node, |
458 | &Info->Address); |
459 | if (ACPI_SUCCESS (Status)) |
460 | { |
461 | Valid |= ACPI_VALID_ADR; |
462 | } |
463 | |
464 | /* Execute the Device._SxW methods */ |
465 | |
466 | Status = AcpiUtExecutePowerMethods (Node, |
467 | AcpiGbl_LowestDstateNames, ACPI_NUM_SxW_METHODS, |
468 | Info->LowestDstates); |
469 | if (ACPI_SUCCESS (Status)) |
470 | { |
471 | Valid |= ACPI_VALID_SXWS; |
472 | } |
473 | |
474 | /* Execute the Device._SxD methods */ |
475 | |
476 | Status = AcpiUtExecutePowerMethods (Node, |
477 | AcpiGbl_HighestDstateNames, ACPI_NUM_SxD_METHODS, |
478 | Info->HighestDstates); |
479 | if (ACPI_SUCCESS (Status)) |
480 | { |
481 | Valid |= ACPI_VALID_SXDS; |
482 | } |
483 | } |
484 | |
485 | /* |
486 | * Create a pointer to the string area of the return buffer. |
487 | * Point to the end of the base ACPI_DEVICE_INFO structure. |
488 | */ |
489 | NextIdString = ACPI_CAST_PTR (char, Info->CompatibleIdList.Ids); |
490 | if (CidList) |
491 | { |
492 | /* Point past the CID PNP_DEVICE_ID array */ |
493 | |
494 | NextIdString += ((ACPI_SIZE) CidList->Count * sizeof (ACPI_PNP_DEVICE_ID)); |
495 | } |
496 | |
497 | /* |
498 | * Copy the HID, UID, and CIDs to the return buffer. The variable-length |
499 | * strings are copied to the reserved area at the end of the buffer. |
500 | * |
501 | * For HID and CID, check if the ID is a PCI Root Bridge. |
502 | */ |
503 | if (Hid) |
504 | { |
505 | NextIdString = AcpiNsCopyDeviceId (&Info->HardwareId, |
506 | Hid, NextIdString); |
507 | |
508 | if (AcpiUtIsPciRootBridge (Hid->String)) |
509 | { |
510 | Info->Flags |= ACPI_PCI_ROOT_BRIDGE; |
511 | } |
512 | } |
513 | |
514 | if (Uid) |
515 | { |
516 | NextIdString = AcpiNsCopyDeviceId (&Info->UniqueId, |
517 | Uid, NextIdString); |
518 | } |
519 | |
520 | if (CidList) |
521 | { |
522 | Info->CompatibleIdList.Count = CidList->Count; |
523 | Info->CompatibleIdList.ListSize = CidList->ListSize; |
524 | |
525 | /* Copy each CID */ |
526 | |
527 | for (i = 0; i < CidList->Count; i++) |
528 | { |
529 | NextIdString = AcpiNsCopyDeviceId (&Info->CompatibleIdList.Ids[i], |
530 | &CidList->Ids[i], NextIdString); |
531 | |
532 | if (AcpiUtIsPciRootBridge (CidList->Ids[i].String)) |
533 | { |
534 | Info->Flags |= ACPI_PCI_ROOT_BRIDGE; |
535 | } |
536 | } |
537 | } |
538 | |
539 | if (Cls) |
540 | { |
541 | NextIdString = AcpiNsCopyDeviceId (&Info->ClassCode, |
542 | Cls, NextIdString); |
543 | } |
544 | |
545 | /* Copy the fixed-length data */ |
546 | |
547 | Info->InfoSize = InfoSize; |
548 | Info->Type = Type; |
549 | Info->Name = Name; |
550 | Info->ParamCount = ParamCount; |
551 | Info->Valid = Valid; |
552 | |
553 | *ReturnBuffer = Info; |
554 | Status = AE_OK; |
555 | |
556 | |
557 | Cleanup: |
558 | if (Hid) |
559 | { |
560 | ACPI_FREE (Hid); |
561 | } |
562 | if (Uid) |
563 | { |
564 | ACPI_FREE (Uid); |
565 | } |
566 | if (CidList) |
567 | { |
568 | ACPI_FREE (CidList); |
569 | } |
570 | if (Cls) |
571 | { |
572 | ACPI_FREE (Cls); |
573 | } |
574 | return (Status); |
575 | } |
576 | |
577 | ACPI_EXPORT_SYMBOL (AcpiGetObjectInfo) |
578 | |
579 | |
580 | /****************************************************************************** |
581 | * |
582 | * FUNCTION: AcpiInstallMethod |
583 | * |
584 | * PARAMETERS: Buffer - An ACPI table containing one control method |
585 | * |
586 | * RETURN: Status |
587 | * |
588 | * DESCRIPTION: Install a control method into the namespace. If the method |
589 | * name already exists in the namespace, it is overwritten. The |
590 | * input buffer must contain a valid DSDT or SSDT containing a |
591 | * single control method. |
592 | * |
593 | ******************************************************************************/ |
594 | |
595 | ACPI_STATUS |
596 | AcpiInstallMethod ( |
597 | UINT8 *Buffer) |
598 | { |
599 | ACPI_TABLE_HEADER *Table = ACPI_CAST_PTR (ACPI_TABLE_HEADER, Buffer); |
600 | UINT8 *AmlBuffer; |
601 | UINT8 *AmlStart; |
602 | char *Path; |
603 | ACPI_NAMESPACE_NODE *Node; |
604 | ACPI_OPERAND_OBJECT *MethodObj; |
605 | ACPI_PARSE_STATE ParserState; |
606 | UINT32 AmlLength; |
607 | UINT16 Opcode; |
608 | UINT8 MethodFlags; |
609 | ACPI_STATUS Status; |
610 | |
611 | |
612 | /* Parameter validation */ |
613 | |
614 | if (!Buffer) |
615 | { |
616 | return (AE_BAD_PARAMETER); |
617 | } |
618 | |
619 | /* Table must be a DSDT or SSDT */ |
620 | |
621 | if (!ACPI_COMPARE_NAME (Table->Signature, ACPI_SIG_DSDT) && |
622 | !ACPI_COMPARE_NAME (Table->Signature, ACPI_SIG_SSDT)) |
623 | { |
624 | return (AE_BAD_HEADER); |
625 | } |
626 | |
627 | /* First AML opcode in the table must be a control method */ |
628 | |
629 | ParserState.Aml = Buffer + sizeof (ACPI_TABLE_HEADER); |
630 | Opcode = AcpiPsPeekOpcode (&ParserState); |
631 | if (Opcode != AML_METHOD_OP) |
632 | { |
633 | return (AE_BAD_PARAMETER); |
634 | } |
635 | |
636 | /* Extract method information from the raw AML */ |
637 | |
638 | ParserState.Aml += AcpiPsGetOpcodeSize (Opcode); |
639 | ParserState.PkgEnd = AcpiPsGetNextPackageEnd (&ParserState); |
640 | Path = AcpiPsGetNextNamestring (&ParserState); |
641 | |
642 | MethodFlags = *ParserState.Aml++; |
643 | AmlStart = ParserState.Aml; |
644 | AmlLength = ACPI_PTR_DIFF (ParserState.PkgEnd, AmlStart); |
645 | |
646 | /* |
647 | * Allocate resources up-front. We don't want to have to delete a new |
648 | * node from the namespace if we cannot allocate memory. |
649 | */ |
650 | AmlBuffer = ACPI_ALLOCATE (AmlLength); |
651 | if (!AmlBuffer) |
652 | { |
653 | return (AE_NO_MEMORY); |
654 | } |
655 | |
656 | MethodObj = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD); |
657 | if (!MethodObj) |
658 | { |
659 | ACPI_FREE (AmlBuffer); |
660 | return (AE_NO_MEMORY); |
661 | } |
662 | |
663 | /* Lock namespace for AcpiNsLookup, we may be creating a new node */ |
664 | |
665 | Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); |
666 | if (ACPI_FAILURE (Status)) |
667 | { |
668 | goto ErrorExit; |
669 | } |
670 | |
671 | /* The lookup either returns an existing node or creates a new one */ |
672 | |
673 | Status = AcpiNsLookup (NULL, Path, ACPI_TYPE_METHOD, ACPI_IMODE_LOAD_PASS1, |
674 | ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND, NULL, &Node); |
675 | |
676 | (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); |
677 | |
678 | if (ACPI_FAILURE (Status)) /* NsLookup */ |
679 | { |
680 | if (Status != AE_ALREADY_EXISTS) |
681 | { |
682 | goto ErrorExit; |
683 | } |
684 | |
685 | /* Node existed previously, make sure it is a method node */ |
686 | |
687 | if (Node->Type != ACPI_TYPE_METHOD) |
688 | { |
689 | Status = AE_TYPE; |
690 | goto ErrorExit; |
691 | } |
692 | } |
693 | |
694 | /* Copy the method AML to the local buffer */ |
695 | |
696 | memcpy (AmlBuffer, AmlStart, AmlLength); |
697 | |
698 | /* Initialize the method object with the new method's information */ |
699 | |
700 | MethodObj->Method.AmlStart = AmlBuffer; |
701 | MethodObj->Method.AmlLength = AmlLength; |
702 | |
703 | MethodObj->Method.ParamCount = (UINT8) |
704 | (MethodFlags & AML_METHOD_ARG_COUNT); |
705 | |
706 | if (MethodFlags & AML_METHOD_SERIALIZED) |
707 | { |
708 | MethodObj->Method.InfoFlags = ACPI_METHOD_SERIALIZED; |
709 | |
710 | MethodObj->Method.SyncLevel = (UINT8) |
711 | ((MethodFlags & AML_METHOD_SYNC_LEVEL) >> 4); |
712 | } |
713 | |
714 | /* |
715 | * Now that it is complete, we can attach the new method object to |
716 | * the method Node (detaches/deletes any existing object) |
717 | */ |
718 | Status = AcpiNsAttachObject (Node, MethodObj, ACPI_TYPE_METHOD); |
719 | |
720 | /* |
721 | * Flag indicates AML buffer is dynamic, must be deleted later. |
722 | * Must be set only after attach above. |
723 | */ |
724 | Node->Flags |= ANOBJ_ALLOCATED_BUFFER; |
725 | |
726 | /* Remove local reference to the method object */ |
727 | |
728 | AcpiUtRemoveReference (MethodObj); |
729 | return (Status); |
730 | |
731 | |
732 | ErrorExit: |
733 | |
734 | ACPI_FREE (AmlBuffer); |
735 | ACPI_FREE (MethodObj); |
736 | return (Status); |
737 | } |
738 | |
739 | ACPI_EXPORT_SYMBOL (AcpiInstallMethod) |
740 | |