1 | /******************************************************************************* |
2 | * |
3 | * Module Name: rscalc - Calculate stream and list lengths |
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 "acresrc.h" |
47 | #include "acnamesp.h" |
48 | |
49 | |
50 | #define _COMPONENT ACPI_RESOURCES |
51 | ACPI_MODULE_NAME ("rscalc" ) |
52 | |
53 | |
54 | /* Local prototypes */ |
55 | |
56 | static UINT8 |
57 | AcpiRsCountSetBits ( |
58 | UINT16 BitField); |
59 | |
60 | static ACPI_RS_LENGTH |
61 | AcpiRsStructOptionLength ( |
62 | ACPI_RESOURCE_SOURCE *ResourceSource); |
63 | |
64 | static UINT32 |
65 | AcpiRsStreamOptionLength ( |
66 | UINT32 ResourceLength, |
67 | UINT32 MinimumTotalLength); |
68 | |
69 | |
70 | /******************************************************************************* |
71 | * |
72 | * FUNCTION: AcpiRsCountSetBits |
73 | * |
74 | * PARAMETERS: BitField - Field in which to count bits |
75 | * |
76 | * RETURN: Number of bits set within the field |
77 | * |
78 | * DESCRIPTION: Count the number of bits set in a resource field. Used for |
79 | * (Short descriptor) interrupt and DMA lists. |
80 | * |
81 | ******************************************************************************/ |
82 | |
83 | static UINT8 |
84 | AcpiRsCountSetBits ( |
85 | UINT16 BitField) |
86 | { |
87 | UINT8 BitsSet; |
88 | |
89 | |
90 | ACPI_FUNCTION_ENTRY (); |
91 | |
92 | |
93 | for (BitsSet = 0; BitField; BitsSet++) |
94 | { |
95 | /* Zero the least significant bit that is set */ |
96 | |
97 | BitField &= (UINT16) (BitField - 1); |
98 | } |
99 | |
100 | return (BitsSet); |
101 | } |
102 | |
103 | |
104 | /******************************************************************************* |
105 | * |
106 | * FUNCTION: AcpiRsStructOptionLength |
107 | * |
108 | * PARAMETERS: ResourceSource - Pointer to optional descriptor field |
109 | * |
110 | * RETURN: Status |
111 | * |
112 | * DESCRIPTION: Common code to handle optional ResourceSourceIndex and |
113 | * ResourceSource fields in some Large descriptors. Used during |
114 | * list-to-stream conversion |
115 | * |
116 | ******************************************************************************/ |
117 | |
118 | static ACPI_RS_LENGTH |
119 | ( |
120 | ACPI_RESOURCE_SOURCE *ResourceSource) |
121 | { |
122 | ACPI_FUNCTION_ENTRY (); |
123 | |
124 | |
125 | /* |
126 | * If the ResourceSource string is valid, return the size of the string |
127 | * (StringLength includes the NULL terminator) plus the size of the |
128 | * ResourceSourceIndex (1). |
129 | */ |
130 | if (ResourceSource->StringPtr) |
131 | { |
132 | return ((ACPI_RS_LENGTH) (ResourceSource->StringLength + 1)); |
133 | } |
134 | |
135 | return (0); |
136 | } |
137 | |
138 | |
139 | /******************************************************************************* |
140 | * |
141 | * FUNCTION: AcpiRsStreamOptionLength |
142 | * |
143 | * PARAMETERS: ResourceLength - Length from the resource header |
144 | * MinimumTotalLength - Minimum length of this resource, before |
145 | * any optional fields. Includes header size |
146 | * |
147 | * RETURN: Length of optional string (0 if no string present) |
148 | * |
149 | * DESCRIPTION: Common code to handle optional ResourceSourceIndex and |
150 | * ResourceSource fields in some Large descriptors. Used during |
151 | * stream-to-list conversion |
152 | * |
153 | ******************************************************************************/ |
154 | |
155 | static UINT32 |
156 | ( |
157 | UINT32 ResourceLength, |
158 | UINT32 MinimumAmlResourceLength) |
159 | { |
160 | UINT32 StringLength = 0; |
161 | |
162 | |
163 | ACPI_FUNCTION_ENTRY (); |
164 | |
165 | |
166 | /* |
167 | * The ResourceSourceIndex and ResourceSource are optional elements of |
168 | * some Large-type resource descriptors. |
169 | */ |
170 | |
171 | /* |
172 | * If the length of the actual resource descriptor is greater than the |
173 | * ACPI spec-defined minimum length, it means that a ResourceSourceIndex |
174 | * exists and is followed by a (required) null terminated string. The |
175 | * string length (including the null terminator) is the resource length |
176 | * minus the minimum length, minus one byte for the ResourceSourceIndex |
177 | * itself. |
178 | */ |
179 | if (ResourceLength > MinimumAmlResourceLength) |
180 | { |
181 | /* Compute the length of the optional string */ |
182 | |
183 | StringLength = ResourceLength - MinimumAmlResourceLength - 1; |
184 | } |
185 | |
186 | /* |
187 | * Round the length up to a multiple of the native word in order to |
188 | * guarantee that the entire resource descriptor is native word aligned |
189 | */ |
190 | return ((UINT32) ACPI_ROUND_UP_TO_NATIVE_WORD (StringLength)); |
191 | } |
192 | |
193 | |
194 | /******************************************************************************* |
195 | * |
196 | * FUNCTION: AcpiRsGetAmlLength |
197 | * |
198 | * PARAMETERS: Resource - Pointer to the resource linked list |
199 | * ResourceListSize - Size of the resource linked list |
200 | * SizeNeeded - Where the required size is returned |
201 | * |
202 | * RETURN: Status |
203 | * |
204 | * DESCRIPTION: Takes a linked list of internal resource descriptors and |
205 | * calculates the size buffer needed to hold the corresponding |
206 | * external resource byte stream. |
207 | * |
208 | ******************************************************************************/ |
209 | |
210 | ACPI_STATUS |
211 | AcpiRsGetAmlLength ( |
212 | ACPI_RESOURCE *Resource, |
213 | ACPI_SIZE ResourceListSize, |
214 | ACPI_SIZE *SizeNeeded) |
215 | { |
216 | ACPI_SIZE AmlSizeNeeded = 0; |
217 | ACPI_RESOURCE *ResourceEnd; |
218 | ACPI_RS_LENGTH TotalSize; |
219 | |
220 | |
221 | ACPI_FUNCTION_TRACE (RsGetAmlLength); |
222 | |
223 | |
224 | /* Traverse entire list of internal resource descriptors */ |
225 | |
226 | ResourceEnd = ACPI_ADD_PTR (ACPI_RESOURCE, Resource, ResourceListSize); |
227 | while (Resource < ResourceEnd) |
228 | { |
229 | /* Validate the descriptor type */ |
230 | |
231 | if (Resource->Type > ACPI_RESOURCE_TYPE_MAX) |
232 | { |
233 | return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE); |
234 | } |
235 | |
236 | /* Sanity check the length. It must not be zero, or we loop forever */ |
237 | |
238 | if (!Resource->Length) |
239 | { |
240 | return_ACPI_STATUS (AE_AML_BAD_RESOURCE_LENGTH); |
241 | } |
242 | |
243 | /* Get the base size of the (external stream) resource descriptor */ |
244 | |
245 | TotalSize = AcpiGbl_AmlResourceSizes [Resource->Type]; |
246 | |
247 | /* |
248 | * Augment the base size for descriptors with optional and/or |
249 | * variable-length fields |
250 | */ |
251 | switch (Resource->Type) |
252 | { |
253 | case ACPI_RESOURCE_TYPE_IRQ: |
254 | |
255 | /* Length can be 3 or 2 */ |
256 | |
257 | if (Resource->Data.Irq.DescriptorLength == 2) |
258 | { |
259 | TotalSize--; |
260 | } |
261 | break; |
262 | |
263 | |
264 | case ACPI_RESOURCE_TYPE_START_DEPENDENT: |
265 | |
266 | /* Length can be 1 or 0 */ |
267 | |
268 | if (Resource->Data.Irq.DescriptorLength == 0) |
269 | { |
270 | TotalSize--; |
271 | } |
272 | break; |
273 | |
274 | |
275 | case ACPI_RESOURCE_TYPE_VENDOR: |
276 | /* |
277 | * Vendor Defined Resource: |
278 | * For a Vendor Specific resource, if the Length is between 1 and 7 |
279 | * it will be created as a Small Resource data type, otherwise it |
280 | * is a Large Resource data type. |
281 | */ |
282 | if (Resource->Data.Vendor.ByteLength > 7) |
283 | { |
284 | /* Base size of a Large resource descriptor */ |
285 | |
286 | TotalSize = sizeof (AML_RESOURCE_LARGE_HEADER); |
287 | } |
288 | |
289 | /* Add the size of the vendor-specific data */ |
290 | |
291 | TotalSize = (ACPI_RS_LENGTH) |
292 | (TotalSize + Resource->Data.Vendor.ByteLength); |
293 | break; |
294 | |
295 | |
296 | case ACPI_RESOURCE_TYPE_END_TAG: |
297 | /* |
298 | * End Tag: |
299 | * We are done -- return the accumulated total size. |
300 | */ |
301 | *SizeNeeded = AmlSizeNeeded + TotalSize; |
302 | |
303 | /* Normal exit */ |
304 | |
305 | return_ACPI_STATUS (AE_OK); |
306 | |
307 | |
308 | case ACPI_RESOURCE_TYPE_ADDRESS16: |
309 | /* |
310 | * 16-Bit Address Resource: |
311 | * Add the size of the optional ResourceSource info |
312 | */ |
313 | TotalSize = (ACPI_RS_LENGTH) (TotalSize + |
314 | AcpiRsStructOptionLength ( |
315 | &Resource->Data.Address16.ResourceSource)); |
316 | break; |
317 | |
318 | |
319 | case ACPI_RESOURCE_TYPE_ADDRESS32: |
320 | /* |
321 | * 32-Bit Address Resource: |
322 | * Add the size of the optional ResourceSource info |
323 | */ |
324 | TotalSize = (ACPI_RS_LENGTH) (TotalSize + |
325 | AcpiRsStructOptionLength ( |
326 | &Resource->Data.Address32.ResourceSource)); |
327 | break; |
328 | |
329 | |
330 | case ACPI_RESOURCE_TYPE_ADDRESS64: |
331 | /* |
332 | * 64-Bit Address Resource: |
333 | * Add the size of the optional ResourceSource info |
334 | */ |
335 | TotalSize = (ACPI_RS_LENGTH) (TotalSize + |
336 | AcpiRsStructOptionLength ( |
337 | &Resource->Data.Address64.ResourceSource)); |
338 | break; |
339 | |
340 | |
341 | case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: |
342 | /* |
343 | * Extended IRQ Resource: |
344 | * Add the size of each additional optional interrupt beyond the |
345 | * required 1 (4 bytes for each UINT32 interrupt number) |
346 | */ |
347 | TotalSize = (ACPI_RS_LENGTH) (TotalSize + |
348 | ((Resource->Data.ExtendedIrq.InterruptCount - 1) * 4) + |
349 | |
350 | /* Add the size of the optional ResourceSource info */ |
351 | |
352 | AcpiRsStructOptionLength ( |
353 | &Resource->Data.ExtendedIrq.ResourceSource)); |
354 | break; |
355 | |
356 | |
357 | case ACPI_RESOURCE_TYPE_GPIO: |
358 | |
359 | TotalSize = (ACPI_RS_LENGTH) (TotalSize + |
360 | (Resource->Data.Gpio.PinTableLength * 2) + |
361 | Resource->Data.Gpio.ResourceSource.StringLength + |
362 | Resource->Data.Gpio.VendorLength); |
363 | |
364 | break; |
365 | |
366 | |
367 | case ACPI_RESOURCE_TYPE_SERIAL_BUS: |
368 | |
369 | TotalSize = AcpiGbl_AmlResourceSerialBusSizes [ |
370 | Resource->Data.CommonSerialBus.Type]; |
371 | |
372 | TotalSize = (ACPI_RS_LENGTH) (TotalSize + |
373 | Resource->Data.I2cSerialBus.ResourceSource.StringLength + |
374 | Resource->Data.I2cSerialBus.VendorLength); |
375 | |
376 | break; |
377 | |
378 | default: |
379 | |
380 | break; |
381 | } |
382 | |
383 | /* Update the total */ |
384 | |
385 | AmlSizeNeeded += TotalSize; |
386 | |
387 | /* Point to the next object */ |
388 | |
389 | Resource = ACPI_ADD_PTR (ACPI_RESOURCE, Resource, Resource->Length); |
390 | } |
391 | |
392 | /* Did not find an EndTag resource descriptor */ |
393 | |
394 | return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG); |
395 | } |
396 | |
397 | |
398 | /******************************************************************************* |
399 | * |
400 | * FUNCTION: AcpiRsGetListLength |
401 | * |
402 | * PARAMETERS: AmlBuffer - Pointer to the resource byte stream |
403 | * AmlBufferLength - Size of AmlBuffer |
404 | * SizeNeeded - Where the size needed is returned |
405 | * |
406 | * RETURN: Status |
407 | * |
408 | * DESCRIPTION: Takes an external resource byte stream and calculates the size |
409 | * buffer needed to hold the corresponding internal resource |
410 | * descriptor linked list. |
411 | * |
412 | ******************************************************************************/ |
413 | |
414 | ACPI_STATUS |
415 | AcpiRsGetListLength ( |
416 | UINT8 *AmlBuffer, |
417 | UINT32 AmlBufferLength, |
418 | ACPI_SIZE *SizeNeeded) |
419 | { |
420 | ACPI_STATUS Status; |
421 | UINT8 *EndAml; |
422 | UINT8 *Buffer; |
423 | UINT32 BufferSize; |
424 | UINT16 Temp16; |
425 | UINT16 ResourceLength; |
426 | UINT32 ; |
427 | UINT8 ResourceIndex; |
428 | UINT8 MinimumAmlResourceLength; |
429 | AML_RESOURCE *AmlResource; |
430 | |
431 | |
432 | ACPI_FUNCTION_TRACE (RsGetListLength); |
433 | |
434 | |
435 | *SizeNeeded = ACPI_RS_SIZE_MIN; /* Minimum size is one EndTag */ |
436 | EndAml = AmlBuffer + AmlBufferLength; |
437 | |
438 | /* Walk the list of AML resource descriptors */ |
439 | |
440 | while (AmlBuffer < EndAml) |
441 | { |
442 | /* Validate the Resource Type and Resource Length */ |
443 | |
444 | Status = AcpiUtValidateResource (NULL, AmlBuffer, &ResourceIndex); |
445 | if (ACPI_FAILURE (Status)) |
446 | { |
447 | /* |
448 | * Exit on failure. Cannot continue because the descriptor length |
449 | * may be bogus also. |
450 | */ |
451 | return_ACPI_STATUS (Status); |
452 | } |
453 | |
454 | AmlResource = (void *) AmlBuffer; |
455 | |
456 | /* Get the resource length and base (minimum) AML size */ |
457 | |
458 | ResourceLength = AcpiUtGetResourceLength (AmlBuffer); |
459 | MinimumAmlResourceLength = AcpiGbl_ResourceAmlSizes[ResourceIndex]; |
460 | |
461 | /* |
462 | * Augment the size for descriptors with optional |
463 | * and/or variable length fields |
464 | */ |
465 | ExtraStructBytes = 0; |
466 | Buffer = AmlBuffer + AcpiUtGetResourceHeaderLength (AmlBuffer); |
467 | |
468 | switch (AcpiUtGetResourceType (AmlBuffer)) |
469 | { |
470 | case ACPI_RESOURCE_NAME_IRQ: |
471 | /* |
472 | * IRQ Resource: |
473 | * Get the number of bits set in the 16-bit IRQ mask |
474 | */ |
475 | ACPI_MOVE_16_TO_16 (&Temp16, Buffer); |
476 | ExtraStructBytes = AcpiRsCountSetBits (Temp16); |
477 | break; |
478 | |
479 | |
480 | case ACPI_RESOURCE_NAME_DMA: |
481 | /* |
482 | * DMA Resource: |
483 | * Get the number of bits set in the 8-bit DMA mask |
484 | */ |
485 | ExtraStructBytes = AcpiRsCountSetBits (*Buffer); |
486 | break; |
487 | |
488 | |
489 | case ACPI_RESOURCE_NAME_VENDOR_SMALL: |
490 | case ACPI_RESOURCE_NAME_VENDOR_LARGE: |
491 | /* |
492 | * Vendor Resource: |
493 | * Get the number of vendor data bytes |
494 | */ |
495 | ExtraStructBytes = ResourceLength; |
496 | |
497 | /* |
498 | * There is already one byte included in the minimum |
499 | * descriptor size. If there are extra struct bytes, |
500 | * subtract one from the count. |
501 | */ |
502 | if (ExtraStructBytes) |
503 | { |
504 | ExtraStructBytes--; |
505 | } |
506 | break; |
507 | |
508 | |
509 | case ACPI_RESOURCE_NAME_END_TAG: |
510 | /* |
511 | * End Tag: This is the normal exit |
512 | */ |
513 | return_ACPI_STATUS (AE_OK); |
514 | |
515 | |
516 | case ACPI_RESOURCE_NAME_ADDRESS32: |
517 | case ACPI_RESOURCE_NAME_ADDRESS16: |
518 | case ACPI_RESOURCE_NAME_ADDRESS64: |
519 | /* |
520 | * Address Resource: |
521 | * Add the size of the optional ResourceSource |
522 | */ |
523 | ExtraStructBytes = AcpiRsStreamOptionLength ( |
524 | ResourceLength, MinimumAmlResourceLength); |
525 | break; |
526 | |
527 | |
528 | case ACPI_RESOURCE_NAME_EXTENDED_IRQ: |
529 | /* |
530 | * Extended IRQ Resource: |
531 | * Using the InterruptTableLength, add 4 bytes for each additional |
532 | * interrupt. Note: at least one interrupt is required and is |
533 | * included in the minimum descriptor size (reason for the -1) |
534 | */ |
535 | ExtraStructBytes = (Buffer[1] - 1) * sizeof (UINT32); |
536 | |
537 | /* Add the size of the optional ResourceSource */ |
538 | |
539 | ExtraStructBytes += AcpiRsStreamOptionLength ( |
540 | ResourceLength - ExtraStructBytes, MinimumAmlResourceLength); |
541 | break; |
542 | |
543 | case ACPI_RESOURCE_NAME_GPIO: |
544 | |
545 | /* Vendor data is optional */ |
546 | |
547 | if (AmlResource->Gpio.VendorLength) |
548 | { |
549 | ExtraStructBytes += |
550 | AmlResource->Gpio.VendorOffset - |
551 | AmlResource->Gpio.PinTableOffset + |
552 | AmlResource->Gpio.VendorLength; |
553 | } |
554 | else |
555 | { |
556 | ExtraStructBytes += |
557 | AmlResource->LargeHeader.ResourceLength + |
558 | sizeof (AML_RESOURCE_LARGE_HEADER) - |
559 | AmlResource->Gpio.PinTableOffset; |
560 | } |
561 | break; |
562 | |
563 | case ACPI_RESOURCE_NAME_SERIAL_BUS: |
564 | |
565 | MinimumAmlResourceLength = AcpiGbl_ResourceAmlSerialBusSizes[ |
566 | AmlResource->CommonSerialBus.Type]; |
567 | ExtraStructBytes += |
568 | AmlResource->CommonSerialBus.ResourceLength - |
569 | MinimumAmlResourceLength; |
570 | break; |
571 | |
572 | default: |
573 | |
574 | break; |
575 | } |
576 | |
577 | /* |
578 | * Update the required buffer size for the internal descriptor structs |
579 | * |
580 | * Important: Round the size up for the appropriate alignment. This |
581 | * is a requirement on IA64. |
582 | */ |
583 | if (AcpiUtGetResourceType (AmlBuffer) == |
584 | ACPI_RESOURCE_NAME_SERIAL_BUS) |
585 | { |
586 | BufferSize = AcpiGbl_ResourceStructSerialBusSizes[ |
587 | AmlResource->CommonSerialBus.Type] + ExtraStructBytes; |
588 | } |
589 | else |
590 | { |
591 | BufferSize = AcpiGbl_ResourceStructSizes[ResourceIndex] + |
592 | ExtraStructBytes; |
593 | } |
594 | |
595 | BufferSize = (UINT32) ACPI_ROUND_UP_TO_NATIVE_WORD (BufferSize); |
596 | *SizeNeeded += BufferSize; |
597 | |
598 | ACPI_DEBUG_PRINT ((ACPI_DB_RESOURCES, |
599 | "Type %.2X, AmlLength %.2X InternalLength %.2X\n" , |
600 | AcpiUtGetResourceType (AmlBuffer), |
601 | AcpiUtGetDescriptorLength (AmlBuffer), BufferSize)); |
602 | |
603 | /* |
604 | * Point to the next resource within the AML stream using the length |
605 | * contained in the resource descriptor header |
606 | */ |
607 | AmlBuffer += AcpiUtGetDescriptorLength (AmlBuffer); |
608 | } |
609 | |
610 | /* Did not find an EndTag resource descriptor */ |
611 | |
612 | return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG); |
613 | } |
614 | |
615 | |
616 | /******************************************************************************* |
617 | * |
618 | * FUNCTION: AcpiRsGetPciRoutingTableLength |
619 | * |
620 | * PARAMETERS: PackageObject - Pointer to the package object |
621 | * BufferSizeNeeded - UINT32 pointer of the size buffer |
622 | * needed to properly return the |
623 | * parsed data |
624 | * |
625 | * RETURN: Status |
626 | * |
627 | * DESCRIPTION: Given a package representing a PCI routing table, this |
628 | * calculates the size of the corresponding linked list of |
629 | * descriptions. |
630 | * |
631 | ******************************************************************************/ |
632 | |
633 | ACPI_STATUS |
634 | AcpiRsGetPciRoutingTableLength ( |
635 | ACPI_OPERAND_OBJECT *PackageObject, |
636 | ACPI_SIZE *BufferSizeNeeded) |
637 | { |
638 | UINT32 NumberOfElements; |
639 | ACPI_SIZE TempSizeNeeded = 0; |
640 | ACPI_OPERAND_OBJECT **TopObjectList; |
641 | UINT32 Index; |
642 | ACPI_OPERAND_OBJECT *PackageElement; |
643 | ACPI_OPERAND_OBJECT **SubObjectList; |
644 | BOOLEAN NameFound; |
645 | UINT32 TableIndex; |
646 | |
647 | |
648 | ACPI_FUNCTION_TRACE (RsGetPciRoutingTableLength); |
649 | |
650 | |
651 | NumberOfElements = PackageObject->Package.Count; |
652 | |
653 | /* |
654 | * Calculate the size of the return buffer. |
655 | * The base size is the number of elements * the sizes of the |
656 | * structures. Additional space for the strings is added below. |
657 | * The minus one is to subtract the size of the UINT8 Source[1] |
658 | * member because it is added below. |
659 | * |
660 | * But each PRT_ENTRY structure has a pointer to a string and |
661 | * the size of that string must be found. |
662 | */ |
663 | TopObjectList = PackageObject->Package.Elements; |
664 | |
665 | for (Index = 0; Index < NumberOfElements; Index++) |
666 | { |
667 | /* Dereference the subpackage */ |
668 | |
669 | PackageElement = *TopObjectList; |
670 | |
671 | /* We must have a valid Package object */ |
672 | |
673 | if (!PackageElement || |
674 | (PackageElement->Common.Type != ACPI_TYPE_PACKAGE)) |
675 | { |
676 | return_ACPI_STATUS (AE_AML_OPERAND_TYPE); |
677 | } |
678 | |
679 | /* |
680 | * The SubObjectList will now point to an array of the |
681 | * four IRQ elements: Address, Pin, Source and SourceIndex |
682 | */ |
683 | SubObjectList = PackageElement->Package.Elements; |
684 | |
685 | /* Scan the IrqTableElements for the Source Name String */ |
686 | |
687 | NameFound = FALSE; |
688 | |
689 | for (TableIndex = 0; |
690 | TableIndex < PackageElement->Package.Count && !NameFound; |
691 | TableIndex++) |
692 | { |
693 | if (*SubObjectList && /* Null object allowed */ |
694 | |
695 | ((ACPI_TYPE_STRING == |
696 | (*SubObjectList)->Common.Type) || |
697 | |
698 | ((ACPI_TYPE_LOCAL_REFERENCE == |
699 | (*SubObjectList)->Common.Type) && |
700 | |
701 | ((*SubObjectList)->Reference.Class == |
702 | ACPI_REFCLASS_NAME)))) |
703 | { |
704 | NameFound = TRUE; |
705 | } |
706 | else |
707 | { |
708 | /* Look at the next element */ |
709 | |
710 | SubObjectList++; |
711 | } |
712 | } |
713 | |
714 | TempSizeNeeded += (sizeof (ACPI_PCI_ROUTING_TABLE) - 4); |
715 | |
716 | /* Was a String type found? */ |
717 | |
718 | if (NameFound) |
719 | { |
720 | if ((*SubObjectList)->Common.Type == ACPI_TYPE_STRING) |
721 | { |
722 | /* |
723 | * The length String.Length field does not include the |
724 | * terminating NULL, add 1 |
725 | */ |
726 | TempSizeNeeded += ((ACPI_SIZE) |
727 | (*SubObjectList)->String.Length + 1); |
728 | } |
729 | else |
730 | { |
731 | TempSizeNeeded += AcpiNsGetPathnameLength ( |
732 | (*SubObjectList)->Reference.Node); |
733 | } |
734 | } |
735 | else |
736 | { |
737 | /* |
738 | * If no name was found, then this is a NULL, which is |
739 | * translated as a UINT32 zero. |
740 | */ |
741 | TempSizeNeeded += sizeof (UINT32); |
742 | } |
743 | |
744 | /* Round up the size since each element must be aligned */ |
745 | |
746 | TempSizeNeeded = ACPI_ROUND_UP_TO_64BIT (TempSizeNeeded); |
747 | |
748 | /* Point to the next ACPI_OPERAND_OBJECT */ |
749 | |
750 | TopObjectList++; |
751 | } |
752 | |
753 | /* |
754 | * Add an extra element to the end of the list, essentially a |
755 | * NULL terminator |
756 | */ |
757 | *BufferSizeNeeded = TempSizeNeeded + sizeof (ACPI_PCI_ROUTING_TABLE); |
758 | return_ACPI_STATUS (AE_OK); |
759 | } |
760 | |