Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.git] / drivers / acpi / resources / rscalc.c
1 /*******************************************************************************
2  *
3  * Module Name: rscalc - Calculate stream and list lengths
4  *
5  ******************************************************************************/
6
7 /*
8  * Copyright (C) 2000 - 2005, R. Byron Moore
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
45 #include <acpi/acpi.h>
46 #include <acpi/acresrc.h>
47 #include <acpi/amlcode.h>
48 #include <acpi/acnamesp.h>
49
50 #define _COMPONENT          ACPI_RESOURCES
51          ACPI_MODULE_NAME    ("rscalc")
52
53
54 /*******************************************************************************
55  *
56  * FUNCTION:    acpi_rs_get_byte_stream_length
57  *
58  * PARAMETERS:  linked_list         - Pointer to the resource linked list
59  *              size_needed         - u32 pointer of the size buffer needed
60  *                                    to properly return the parsed data
61  *
62  * RETURN:      Status
63  *
64  * DESCRIPTION: Takes the resource byte stream and parses it once, calculating
65  *              the size buffer needed to hold the linked list that conveys
66  *              the resource data.
67  *
68  ******************************************************************************/
69
70 acpi_status
71 acpi_rs_get_byte_stream_length (
72         struct acpi_resource            *linked_list,
73         acpi_size                       *size_needed)
74 {
75         acpi_size                       byte_stream_size_needed = 0;
76         acpi_size                       segment_size;
77         u8                              done = FALSE;
78
79
80         ACPI_FUNCTION_TRACE ("rs_get_byte_stream_length");
81
82
83         while (!done) {
84                 /*
85                  * Init the variable that will hold the size to add to the total.
86                  */
87                 segment_size = 0;
88
89                 switch (linked_list->id) {
90                 case ACPI_RSTYPE_IRQ:
91                         /*
92                          * IRQ Resource
93                          * For an IRQ Resource, Byte 3, although optional, will always be
94                          * created - it holds IRQ information.
95                          */
96                         segment_size = 4;
97                         break;
98
99                 case ACPI_RSTYPE_DMA:
100                         /*
101                          * DMA Resource
102                          * For this resource the size is static
103                          */
104                         segment_size = 3;
105                         break;
106
107                 case ACPI_RSTYPE_START_DPF:
108                         /*
109                          * Start Dependent Functions Resource
110                          * For a start_dependent_functions Resource, Byte 1, although
111                          * optional, will always be created.
112                          */
113                         segment_size = 2;
114                         break;
115
116                 case ACPI_RSTYPE_END_DPF:
117                         /*
118                          * End Dependent Functions Resource
119                          * For this resource the size is static
120                          */
121                         segment_size = 1;
122                         break;
123
124                 case ACPI_RSTYPE_IO:
125                         /*
126                          * IO Port Resource
127                          * For this resource the size is static
128                          */
129                         segment_size = 8;
130                         break;
131
132                 case ACPI_RSTYPE_FIXED_IO:
133                         /*
134                          * Fixed IO Port Resource
135                          * For this resource the size is static
136                          */
137                         segment_size = 4;
138                         break;
139
140                 case ACPI_RSTYPE_VENDOR:
141                         /*
142                          * Vendor Defined Resource
143                          * For a Vendor Specific resource, if the Length is between 1 and 7
144                          * it will be created as a Small Resource data type, otherwise it
145                          * is a Large Resource data type.
146                          */
147                         if (linked_list->data.vendor_specific.length > 7) {
148                                 segment_size = 3;
149                         }
150                         else {
151                                 segment_size = 1;
152                         }
153                         segment_size += linked_list->data.vendor_specific.length;
154                         break;
155
156                 case ACPI_RSTYPE_END_TAG:
157                         /*
158                          * End Tag
159                          * For this resource the size is static
160                          */
161                         segment_size = 2;
162                         done = TRUE;
163                         break;
164
165                 case ACPI_RSTYPE_MEM24:
166                         /*
167                          * 24-Bit Memory Resource
168                          * For this resource the size is static
169                          */
170                         segment_size = 12;
171                         break;
172
173                 case ACPI_RSTYPE_MEM32:
174                         /*
175                          * 32-Bit Memory Range Resource
176                          * For this resource the size is static
177                          */
178                         segment_size = 20;
179                         break;
180
181                 case ACPI_RSTYPE_FIXED_MEM32:
182                         /*
183                          * 32-Bit Fixed Memory Resource
184                          * For this resource the size is static
185                          */
186                         segment_size = 12;
187                         break;
188
189                 case ACPI_RSTYPE_ADDRESS16:
190                         /*
191                          * 16-Bit Address Resource
192                          * The base size of this byte stream is 16. If a Resource Source
193                          * string is not NULL, add 1 for the Index + the length of the null
194                          * terminated string Resource Source + 1 for the null.
195                          */
196                         segment_size = 16;
197
198                         if (linked_list->data.address16.resource_source.string_ptr) {
199                                 segment_size += linked_list->data.address16.resource_source.string_length;
200                                 segment_size++;
201                         }
202                         break;
203
204                 case ACPI_RSTYPE_ADDRESS32:
205                         /*
206                          * 32-Bit Address Resource
207                          * The base size of this byte stream is 26. If a Resource
208                          * Source string is not NULL, add 1 for the Index + the
209                          * length of the null terminated string Resource Source +
210                          * 1 for the null.
211                          */
212                         segment_size = 26;
213
214                         if (linked_list->data.address32.resource_source.string_ptr) {
215                                 segment_size += linked_list->data.address32.resource_source.string_length;
216                                 segment_size++;
217                         }
218                         break;
219
220                 case ACPI_RSTYPE_ADDRESS64:
221                         /*
222                          * 64-Bit Address Resource
223                          * The base size of this byte stream is 46. If a resource_source
224                          * string is not NULL, add 1 for the Index + the length of the null
225                          * terminated string Resource Source + 1 for the null.
226                          */
227                         segment_size = 46;
228
229                         if (linked_list->data.address64.resource_source.string_ptr) {
230                                 segment_size += linked_list->data.address64.resource_source.string_length;
231                                 segment_size++;
232                         }
233                         break;
234
235                 case ACPI_RSTYPE_EXT_IRQ:
236                         /*
237                          * Extended IRQ Resource
238                          * The base size of this byte stream is 9. This is for an Interrupt
239                          * table length of 1.  For each additional interrupt, add 4.
240                          * If a Resource Source string is not NULL, add 1 for the
241                          * Index + the length of the null terminated string
242                          * Resource Source + 1 for the null.
243                          */
244                         segment_size = 9 +
245                                 (((acpi_size) linked_list->data.extended_irq.number_of_interrupts - 1) * 4);
246
247                         if (linked_list->data.extended_irq.resource_source.string_ptr) {
248                                 segment_size += linked_list->data.extended_irq.resource_source.string_length;
249                                 segment_size++;
250                         }
251                         break;
252
253                 default:
254                         /*
255                          * If we get here, everything is out of sync, exit with error
256                          */
257                         return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE);
258
259                 } /* switch (linked_list->Id) */
260
261                 /*
262                  * Update the total
263                  */
264                 byte_stream_size_needed += segment_size;
265
266                 /*
267                  * Point to the next object
268                  */
269                 linked_list = ACPI_PTR_ADD (struct acpi_resource,
270                                   linked_list, linked_list->length);
271         }
272
273         /*
274          * This is the data the caller needs
275          */
276         *size_needed = byte_stream_size_needed;
277         return_ACPI_STATUS (AE_OK);
278 }
279
280
281 /*******************************************************************************
282  *
283  * FUNCTION:    acpi_rs_get_list_length
284  *
285  * PARAMETERS:  byte_stream_buffer      - Pointer to the resource byte stream
286  *              byte_stream_buffer_length - Size of byte_stream_buffer
287  *              size_needed             - u32 pointer of the size buffer
288  *                                        needed to properly return the
289  *                                        parsed data
290  *
291  * RETURN:      Status
292  *
293  * DESCRIPTION: Takes the resource byte stream and parses it once, calculating
294  *              the size buffer needed to hold the linked list that conveys
295  *              the resource data.
296  *
297  ******************************************************************************/
298
299 acpi_status
300 acpi_rs_get_list_length (
301         u8                              *byte_stream_buffer,
302         u32                             byte_stream_buffer_length,
303         acpi_size                       *size_needed)
304 {
305         u32                             buffer_size = 0;
306         u32                             bytes_parsed = 0;
307         u8                              number_of_interrupts = 0;
308         u8                              number_of_channels = 0;
309         u8                              resource_type;
310         u32                             structure_size;
311         u32                             bytes_consumed;
312         u8                              *buffer;
313         u8                              temp8;
314         u16                             temp16;
315         u8                              index;
316         u8                              additional_bytes;
317
318
319         ACPI_FUNCTION_TRACE ("rs_get_list_length");
320
321
322         while (bytes_parsed < byte_stream_buffer_length) {
323                 /*
324                  * The next byte in the stream is the resource type
325                  */
326                 resource_type = acpi_rs_get_resource_type (*byte_stream_buffer);
327
328                 switch (resource_type) {
329                 case ACPI_RDESC_TYPE_MEMORY_24:
330                         /*
331                          * 24-Bit Memory Resource
332                          */
333                         bytes_consumed = 12;
334
335                         structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_mem24);
336                         break;
337
338
339                 case ACPI_RDESC_TYPE_LARGE_VENDOR:
340                         /*
341                          * Vendor Defined Resource
342                          */
343                         buffer = byte_stream_buffer;
344                         ++buffer;
345
346                         ACPI_MOVE_16_TO_16 (&temp16, buffer);
347                         bytes_consumed = temp16 + 3;
348
349                         /*
350                          * Ensure a 32-bit boundary for the structure
351                          */
352                         temp16 = (u16) ACPI_ROUND_UP_to_32_bITS (temp16);
353
354                         structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_vendor) +
355                                            (temp16 * sizeof (u8));
356                         break;
357
358
359                 case ACPI_RDESC_TYPE_MEMORY_32:
360                         /*
361                          * 32-Bit Memory Range Resource
362                          */
363                         bytes_consumed = 20;
364
365                         structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_mem32);
366                         break;
367
368
369                 case ACPI_RDESC_TYPE_FIXED_MEMORY_32:
370                         /*
371                          * 32-Bit Fixed Memory Resource
372                          */
373                         bytes_consumed = 12;
374
375                         structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_fixed_mem32);
376                         break;
377
378
379                 case ACPI_RDESC_TYPE_EXTENDED_ADDRESS_SPACE:
380                         /*
381                          * 64-Bit Address Resource
382                          */
383                         buffer = byte_stream_buffer;
384
385                         ++buffer;
386                         ACPI_MOVE_16_TO_16 (&temp16, buffer);
387
388                         bytes_consumed = temp16 + 3;
389                         structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address64);
390                         break;
391
392
393                 case ACPI_RDESC_TYPE_QWORD_ADDRESS_SPACE:
394                         /*
395                          * 64-Bit Address Resource
396                          */
397                         buffer = byte_stream_buffer;
398
399                         ++buffer;
400                         ACPI_MOVE_16_TO_16 (&temp16, buffer);
401
402                         bytes_consumed = temp16 + 3;
403
404                         /*
405                          * Resource Source Index and Resource Source are optional elements.
406                          * Check the length of the Bytestream.  If it is greater than 43,
407                          * that means that an Index exists and is followed by a null
408                          * terminated string.  Therefore, set the temp variable to the
409                          * length minus the minimum byte stream length plus the byte for
410                          * the Index to determine the size of the NULL terminated string.
411                          */
412                         if (43 < temp16) {
413                                 temp8 = (u8) (temp16 - 44);
414                         }
415                         else {
416                                 temp8 = 0;
417                         }
418
419                         /*
420                          * Ensure a 64-bit boundary for the structure
421                          */
422                         temp8 = (u8) ACPI_ROUND_UP_to_64_bITS (temp8);
423
424                         structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address64) +
425                                            (temp8 * sizeof (u8));
426                         break;
427
428
429                 case ACPI_RDESC_TYPE_DWORD_ADDRESS_SPACE:
430                         /*
431                          * 32-Bit Address Resource
432                          */
433                         buffer = byte_stream_buffer;
434
435                         ++buffer;
436                         ACPI_MOVE_16_TO_16 (&temp16, buffer);
437
438                         bytes_consumed = temp16 + 3;
439
440                         /*
441                          * Resource Source Index and Resource Source are optional elements.
442                          * Check the length of the Bytestream.  If it is greater than 23,
443                          * that means that an Index exists and is followed by a null
444                          * terminated string.  Therefore, set the temp variable to the
445                          * length minus the minimum byte stream length plus the byte for
446                          * the Index to determine the size of the NULL terminated string.
447                          */
448                         if (23 < temp16) {
449                                 temp8 = (u8) (temp16 - 24);
450                         }
451                         else {
452                                 temp8 = 0;
453                         }
454
455                         /*
456                          * Ensure a 32-bit boundary for the structure
457                          */
458                         temp8 = (u8) ACPI_ROUND_UP_to_32_bITS (temp8);
459
460                         structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address32) +
461                                            (temp8 * sizeof (u8));
462                         break;
463
464
465                 case ACPI_RDESC_TYPE_WORD_ADDRESS_SPACE:
466                         /*
467                          * 16-Bit Address Resource
468                          */
469                         buffer = byte_stream_buffer;
470
471                         ++buffer;
472                         ACPI_MOVE_16_TO_16 (&temp16, buffer);
473
474                         bytes_consumed = temp16 + 3;
475
476                         /*
477                          * Resource Source Index and Resource Source are optional elements.
478                          * Check the length of the Bytestream.  If it is greater than 13,
479                          * that means that an Index exists and is followed by a null
480                          * terminated string.  Therefore, set the temp variable to the
481                          * length minus the minimum byte stream length plus the byte for
482                          * the Index to determine the size of the NULL terminated string.
483                          */
484                         if (13 < temp16) {
485                                 temp8 = (u8) (temp16 - 14);
486                         }
487                         else {
488                                 temp8 = 0;
489                         }
490
491                         /*
492                          * Ensure a 32-bit boundary for the structure
493                          */
494                         temp8 = (u8) ACPI_ROUND_UP_to_32_bITS (temp8);
495
496                         structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address16) +
497                                            (temp8 * sizeof (u8));
498                         break;
499
500
501                 case ACPI_RDESC_TYPE_EXTENDED_XRUPT:
502                         /*
503                          * Extended IRQ
504                          */
505                         buffer = byte_stream_buffer;
506
507                         ++buffer;
508                         ACPI_MOVE_16_TO_16 (&temp16, buffer);
509
510                         bytes_consumed = temp16 + 3;
511
512                         /*
513                          * Point past the length field and the Interrupt vector flags to
514                          * save off the Interrupt table length to the Temp8 variable.
515                          */
516                         buffer += 3;
517                         temp8 = *buffer;
518
519                         /*
520                          * To compensate for multiple interrupt numbers, add 4 bytes for
521                          * each additional interrupts greater than 1
522                          */
523                         additional_bytes = (u8) ((temp8 - 1) * 4);
524
525                         /*
526                          * Resource Source Index and Resource Source are optional elements.
527                          * Check the length of the Bytestream.  If it is greater than 9,
528                          * that means that an Index exists and is followed by a null
529                          * terminated string.  Therefore, set the temp variable to the
530                          * length minus the minimum byte stream length plus the byte for
531                          * the Index to determine the size of the NULL terminated string.
532                          */
533                         if (9 + additional_bytes < temp16) {
534                                 temp8 = (u8) (temp16 - (9 + additional_bytes));
535                         }
536                         else {
537                                 temp8 = 0;
538                         }
539
540                         /*
541                          * Ensure a 32-bit boundary for the structure
542                          */
543                         temp8 = (u8) ACPI_ROUND_UP_to_32_bITS (temp8);
544
545                         structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_ext_irq) +
546                                            (additional_bytes * sizeof (u8)) +
547                                            (temp8 * sizeof (u8));
548                         break;
549
550
551                 case ACPI_RDESC_TYPE_IRQ_FORMAT:
552                         /*
553                          * IRQ Resource.
554                          * Determine if it there are two or three trailing bytes
555                          */
556                         buffer = byte_stream_buffer;
557                         temp8 = *buffer;
558
559                         if(temp8 & 0x01) {
560                                 bytes_consumed = 4;
561                         }
562                         else {
563                                 bytes_consumed = 3;
564                         }
565
566                         /* Point past the descriptor */
567
568                         ++buffer;
569
570                         /*
571                          * Look at the number of bits set
572                          */
573                         ACPI_MOVE_16_TO_16 (&temp16, buffer);
574
575                         for (index = 0; index < 16; index++) {
576                                 if (temp16 & 0x1) {
577                                         ++number_of_interrupts;
578                                 }
579
580                                 temp16 >>= 1;
581                         }
582
583                         structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_io) +
584                                            (number_of_interrupts * sizeof (u32));
585                         break;
586
587
588                 case ACPI_RDESC_TYPE_DMA_FORMAT:
589                         /*
590                          * DMA Resource
591                          */
592                         buffer = byte_stream_buffer;
593                         bytes_consumed = 3;
594
595                         /* Point past the descriptor */
596
597                         ++buffer;
598
599                         /*
600                          * Look at the number of bits set
601                          */
602                         temp8 = *buffer;
603
604                         for(index = 0; index < 8; index++) {
605                                 if(temp8 & 0x1) {
606                                         ++number_of_channels;
607                                 }
608
609                                 temp8 >>= 1;
610                         }
611
612                         structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_dma) +
613                                            (number_of_channels * sizeof (u32));
614                         break;
615
616
617                 case ACPI_RDESC_TYPE_START_DEPENDENT:
618                         /*
619                          * Start Dependent Functions Resource
620                          * Determine if it there are two or three trailing bytes
621                          */
622                         buffer = byte_stream_buffer;
623                         temp8 = *buffer;
624
625                         if(temp8 & 0x01) {
626                                 bytes_consumed = 2;
627                         }
628                         else {
629                                 bytes_consumed = 1;
630                         }
631
632                         structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_start_dpf);
633                         break;
634
635
636                 case ACPI_RDESC_TYPE_END_DEPENDENT:
637                         /*
638                          * End Dependent Functions Resource
639                          */
640                         bytes_consumed = 1;
641                         structure_size = ACPI_RESOURCE_LENGTH;
642                         break;
643
644
645                 case ACPI_RDESC_TYPE_IO_PORT:
646                         /*
647                          * IO Port Resource
648                          */
649                         bytes_consumed = 8;
650                         structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_io);
651                         break;
652
653
654                 case ACPI_RDESC_TYPE_FIXED_IO_PORT:
655                         /*
656                          * Fixed IO Port Resource
657                          */
658                         bytes_consumed = 4;
659                         structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_fixed_io);
660                         break;
661
662
663                 case ACPI_RDESC_TYPE_SMALL_VENDOR:
664                         /*
665                          * Vendor Specific Resource
666                          */
667                         buffer = byte_stream_buffer;
668
669                         temp8 = *buffer;
670                         temp8 = (u8) (temp8 & 0x7);
671                         bytes_consumed = temp8 + 1;
672
673                         /*
674                          * Ensure a 32-bit boundary for the structure
675                          */
676                         temp8 = (u8) ACPI_ROUND_UP_to_32_bITS (temp8);
677                         structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_vendor) +
678                                            (temp8 * sizeof (u8));
679                         break;
680
681
682                 case ACPI_RDESC_TYPE_END_TAG:
683                         /*
684                          * End Tag
685                          */
686                         bytes_consumed = 2;
687                         structure_size = ACPI_RESOURCE_LENGTH;
688                         byte_stream_buffer_length = bytes_parsed;
689                         break;
690
691
692                 default:
693                         /*
694                          * If we get here, everything is out of sync,
695                          * exit with an error
696                          */
697                         return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE);
698                 }
699
700                 /*
701                  * Update the return value and counter
702                  */
703                 buffer_size += (u32) ACPI_ALIGN_RESOURCE_SIZE (structure_size);
704                 bytes_parsed += bytes_consumed;
705
706                 /*
707                  * Set the byte stream to point to the next resource
708                  */
709                 byte_stream_buffer += bytes_consumed;
710         }
711
712         /*
713          * This is the data the caller needs
714          */
715         *size_needed = buffer_size;
716         return_ACPI_STATUS (AE_OK);
717 }
718
719
720 /*******************************************************************************
721  *
722  * FUNCTION:    acpi_rs_get_pci_routing_table_length
723  *
724  * PARAMETERS:  package_object          - Pointer to the package object
725  *              buffer_size_needed      - u32 pointer of the size buffer
726  *                                        needed to properly return the
727  *                                        parsed data
728  *
729  * RETURN:      Status
730  *
731  * DESCRIPTION: Given a package representing a PCI routing table, this
732  *              calculates the size of the corresponding linked list of
733  *              descriptions.
734  *
735  ******************************************************************************/
736
737 acpi_status
738 acpi_rs_get_pci_routing_table_length (
739         union acpi_operand_object       *package_object,
740         acpi_size                       *buffer_size_needed)
741 {
742         u32                             number_of_elements;
743         acpi_size                       temp_size_needed = 0;
744         union acpi_operand_object       **top_object_list;
745         u32                             index;
746         union acpi_operand_object       *package_element;
747         union acpi_operand_object       **sub_object_list;
748         u8                              name_found;
749         u32                             table_index;
750
751
752         ACPI_FUNCTION_TRACE ("rs_get_pci_routing_table_length");
753
754
755         number_of_elements = package_object->package.count;
756
757         /*
758          * Calculate the size of the return buffer.
759          * The base size is the number of elements * the sizes of the
760          * structures.  Additional space for the strings is added below.
761          * The minus one is to subtract the size of the u8 Source[1]
762          * member because it is added below.
763          *
764          * But each PRT_ENTRY structure has a pointer to a string and
765          * the size of that string must be found.
766          */
767         top_object_list = package_object->package.elements;
768
769         for (index = 0; index < number_of_elements; index++) {
770                 /*
771                  * Dereference the sub-package
772                  */
773                 package_element = *top_object_list;
774
775                 /*
776                  * The sub_object_list will now point to an array of the
777                  * four IRQ elements: Address, Pin, Source and source_index
778                  */
779                 sub_object_list = package_element->package.elements;
780
781                 /*
782                  * Scan the irq_table_elements for the Source Name String
783                  */
784                 name_found = FALSE;
785
786                 for (table_index = 0; table_index < 4 && !name_found; table_index++) {
787                         if ((ACPI_TYPE_STRING == ACPI_GET_OBJECT_TYPE (*sub_object_list)) ||
788                                 ((ACPI_TYPE_LOCAL_REFERENCE == ACPI_GET_OBJECT_TYPE (*sub_object_list)) &&
789                                         ((*sub_object_list)->reference.opcode == AML_INT_NAMEPATH_OP))) {
790                                 name_found = TRUE;
791                         }
792                         else {
793                                 /*
794                                  * Look at the next element
795                                  */
796                                 sub_object_list++;
797                         }
798                 }
799
800                 temp_size_needed += (sizeof (struct acpi_pci_routing_table) - 4);
801
802                 /*
803                  * Was a String type found?
804                  */
805                 if (name_found) {
806                         if (ACPI_GET_OBJECT_TYPE (*sub_object_list) == ACPI_TYPE_STRING) {
807                                 /*
808                                  * The length String.Length field does not include the
809                                  * terminating NULL, add 1
810                                  */
811                                 temp_size_needed += ((acpi_size) (*sub_object_list)->string.length + 1);
812                         }
813                         else {
814                                 temp_size_needed += acpi_ns_get_pathname_length (
815                                                    (*sub_object_list)->reference.node);
816                         }
817                 }
818                 else {
819                         /*
820                          * If no name was found, then this is a NULL, which is
821                          * translated as a u32 zero.
822                          */
823                         temp_size_needed += sizeof (u32);
824                 }
825
826                 /* Round up the size since each element must be aligned */
827
828                 temp_size_needed = ACPI_ROUND_UP_to_64_bITS (temp_size_needed);
829
830                 /*
831                  * Point to the next union acpi_operand_object
832                  */
833                 top_object_list++;
834         }
835
836         /*
837          * Adding an extra element to the end of the list, essentially a NULL terminator
838          */
839         *buffer_size_needed = temp_size_needed + sizeof (struct acpi_pci_routing_table);
840         return_ACPI_STATUS (AE_OK);
841 }