- Make ACPI use PCH. Cuts down compile time to 9 seconds on gcc.
[reactos.git] / reactos / drivers / bus / acpi / resource / rscalc.c
1 /*******************************************************************************
2 *
3 * Module Name: rscalc - Acpi_rs_calculate_byte_stream_length
4 * Acpi_rs_calculate_list_length
5 * $Revision: 1.1 $
6 *
7 ******************************************************************************/
8
9 /*
10 * Copyright (C) 2000, 2001 R. Byron Moore
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
27
28 #include <acpi.h>
29
30 #define _COMPONENT ACPI_RESOURCES
31 MODULE_NAME ("rscalc")
32
33
34 /*******************************************************************************
35 *
36 * FUNCTION: Acpi_rs_calculate_byte_stream_length
37 *
38 * PARAMETERS: Linked_list - Pointer to the resource linked list
39 * Size_needed - u32 pointer of the size buffer needed
40 * to properly return the parsed data
41 *
42 * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
43 *
44 * DESCRIPTION: Takes the resource byte stream and parses it once, calculating
45 * the size buffer needed to hold the linked list that conveys
46 * the resource data.
47 *
48 ******************************************************************************/
49
50 ACPI_STATUS
51 acpi_rs_calculate_byte_stream_length (
52 RESOURCE *linked_list,
53 u32 *size_needed)
54 {
55 u32 byte_stream_size_needed = 0;
56 u32 segment_size;
57 EXTENDED_IRQ_RESOURCE *ex_irq = NULL;
58 u8 done = FALSE;
59
60
61 while (!done) {
62
63 /*
64 * Init the variable that will hold the size to add to the
65 * total.
66 */
67 segment_size = 0;
68
69 switch (linked_list->id) {
70 case irq:
71 /*
72 * IRQ Resource
73 */
74 /*
75 * For an IRQ Resource, Byte 3, although optional, will
76 * always be created - it holds IRQ information.
77 */
78 segment_size = 4;
79 break;
80
81 case dma:
82 /*
83 * DMA Resource
84 */
85 /*
86 * For this resource the size is static
87 */
88 segment_size = 3;
89 break;
90
91 case start_dependent_functions:
92 /*
93 * Start Dependent Functions Resource
94 */
95 /*
96 * For a Start_dependent_functions Resource, Byte 1,
97 * although optional, will always be created.
98 */
99 segment_size = 2;
100 break;
101
102 case end_dependent_functions:
103 /*
104 * End Dependent Functions Resource
105 */
106 /*
107 * For this resource the size is static
108 */
109 segment_size = 1;
110 break;
111
112 case io:
113 /*
114 * IO Port Resource
115 */
116 /*
117 * For this resource the size is static
118 */
119 segment_size = 8;
120 break;
121
122 case fixed_io:
123 /*
124 * Fixed IO Port Resource
125 */
126 /*
127 * For this resource the size is static
128 */
129 segment_size = 4;
130 break;
131
132 case vendor_specific:
133 /*
134 * Vendor Defined Resource
135 */
136 /*
137 * For a Vendor Specific resource, if the Length is
138 * between 1 and 7 it will be created as a Small
139 * Resource data type, otherwise it is a Large
140 * Resource data type.
141 */
142 if(linked_list->data.vendor_specific.length > 7) {
143 segment_size = 3;
144 }
145 else {
146 segment_size = 1;
147 }
148 segment_size +=
149 linked_list->data.vendor_specific.length;
150 break;
151
152 case end_tag:
153 /*
154 * End Tag
155 */
156 /*
157 * For this resource the size is static
158 */
159 segment_size = 2;
160 done = TRUE;
161 break;
162
163 case memory24:
164 /*
165 * 24-Bit Memory Resource
166 */
167 /*
168 * For this resource the size is static
169 */
170 segment_size = 12;
171 break;
172
173 case memory32:
174 /*
175 * 32-Bit Memory Range Resource
176 */
177 /*
178 * For this resource the size is static
179 */
180 segment_size = 20;
181 break;
182
183 case fixed_memory32:
184 /*
185 * 32-Bit Fixed Memory Resource
186 */
187 /*
188 * For this resource the size is static
189 */
190 segment_size = 12;
191 break;
192
193 case address16:
194 /*
195 * 16-Bit Address Resource
196 */
197 /*
198 * The base size of this byte stream is 16. If a
199 * Resource Source string is not NULL, add 1 for
200 * the Index + the length of the null terminated
201 * string Resource Source + 1 for the null.
202 */
203 segment_size = 16;
204
205 if(NULL != linked_list->data.address16.resource_source) {
206 segment_size += (1 +
207 linked_list->data.address16.resource_source_string_length);
208 }
209 break;
210
211 case address32:
212 /*
213 * 32-Bit Address Resource
214 */
215 /*
216 * The base size of this byte stream is 26. If a Resource
217 * Source string is not NULL, add 1 for the Index + the
218 * length of the null terminated string Resource Source +
219 * 1 for the null.
220 */
221 segment_size = 26;
222
223 if(NULL != linked_list->data.address16.resource_source) {
224 segment_size += (1 +
225 linked_list->data.address16.resource_source_string_length);
226 }
227 break;
228
229 case extended_irq:
230 /*
231 * Extended IRQ Resource
232 */
233 /*
234 * The base size of this byte stream is 9. This is for an
235 * Interrupt table length of 1. For each additional
236 * interrupt, add 4.
237 * If a Resource Source string is not NULL, add 1 for the
238 * Index + the length of the null terminated string
239 * Resource Source + 1 for the null.
240 */
241 segment_size = 9;
242
243 segment_size +=
244 (linked_list->data.extended_irq.number_of_interrupts -
245 1) * 4;
246
247 if(NULL != ex_irq->resource_source) {
248 segment_size += (1 +
249 linked_list->data.extended_irq.resource_source_string_length);
250 }
251 break;
252
253 default:
254 /*
255 * If we get here, everything is out of sync,
256 * so exit with an error
257 */
258 return (AE_AML_ERROR);
259 break;
260
261 } /* switch (Linked_list->Id) */
262
263 /*
264 * Update the total
265 */
266 byte_stream_size_needed += segment_size;
267
268 /*
269 * Point to the next object
270 */
271 linked_list = (RESOURCE *) ((NATIVE_UINT) linked_list +
272 (NATIVE_UINT) linked_list->length);
273 }
274
275 /*
276 * This is the data the caller needs
277 */
278 *size_needed = byte_stream_size_needed;
279
280 return (AE_OK);
281 }
282
283
284 /*******************************************************************************
285 *
286 * FUNCTION: Acpi_rs_calculate_list_length
287 *
288 * PARAMETERS: Byte_stream_buffer - Pointer to the resource byte stream
289 * Byte_stream_buffer_length - Size of Byte_stream_buffer
290 * Size_needed - u32 pointer of the size buffer
291 * needed to properly return the
292 * parsed data
293 *
294 * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
295 *
296 * DESCRIPTION: Takes the resource byte stream and parses it once, calculating
297 * the size buffer needed to hold the linked list that conveys
298 * the resource data.
299 *
300 ******************************************************************************/
301
302 ACPI_STATUS
303 acpi_rs_calculate_list_length (
304 u8 *byte_stream_buffer,
305 u32 byte_stream_buffer_length,
306 u32 *size_needed)
307 {
308 u32 buffer_size = 0;
309 u32 bytes_parsed = 0;
310 u8 number_of_interrupts = 0;
311 u8 number_of_channels = 0;
312 u8 resource_type;
313 u32 structure_size;
314 u32 bytes_consumed;
315 u8 *buffer;
316 u8 temp8;
317 u16 temp16;
318 u8 index;
319 u8 additional_bytes;
320
321
322 while (bytes_parsed < byte_stream_buffer_length) {
323 /*
324 * Look at the next byte in the stream
325 */
326 resource_type = *byte_stream_buffer;
327
328 /*
329 * See if this is a small or large resource
330 */
331 if(resource_type & 0x80) {
332 /*
333 * Large Resource Type
334 */
335 switch (resource_type) {
336 case MEMORY_RANGE_24:
337 /*
338 * 24-Bit Memory Resource
339 */
340 bytes_consumed = 12;
341
342 structure_size = sizeof (MEMORY24_RESOURCE) +
343 RESOURCE_LENGTH_NO_DATA;
344 break;
345
346 case LARGE_VENDOR_DEFINED:
347 /*
348 * Vendor Defined Resource
349 */
350 buffer = byte_stream_buffer;
351 ++buffer;
352
353 MOVE_UNALIGNED16_TO_16 (&temp16, buffer);
354 bytes_consumed = temp16 + 3;
355
356 /*
357 * Ensure a 32-bit boundary for the structure
358 */
359 temp16 = (u16) ROUND_UP_TO_32_bITS (temp16);
360
361 structure_size = sizeof (VENDOR_RESOURCE) +
362 RESOURCE_LENGTH_NO_DATA +
363 (temp16 * sizeof (u8));
364 break;
365
366 case MEMORY_RANGE_32:
367 /*
368 * 32-Bit Memory Range Resource
369 */
370
371 bytes_consumed = 20;
372
373 structure_size = sizeof (MEMORY32_RESOURCE) +
374 RESOURCE_LENGTH_NO_DATA;
375 break;
376
377 case FIXED_MEMORY_RANGE_32:
378 /*
379 * 32-Bit Fixed Memory Resource
380 */
381 bytes_consumed = 12;
382
383 structure_size = sizeof(FIXED_MEMORY32_RESOURCE) +
384 RESOURCE_LENGTH_NO_DATA;
385 break;
386
387 case DWORD_ADDRESS_SPACE:
388 /*
389 * 32-Bit Address Resource
390 */
391 buffer = byte_stream_buffer;
392
393 ++buffer;
394 MOVE_UNALIGNED16_TO_16 (&temp16, buffer);
395
396 bytes_consumed = temp16 + 3;
397
398 /*
399 * Resource Source Index and Resource Source are
400 * optional elements. Check the length of the
401 * Bytestream. If it is greater than 23, that
402 * means that an Index exists and is followed by
403 * a null termininated string. Therefore, set
404 * the temp variable to the length minus the minimum
405 * byte stream length plus the byte for the Index to
406 * determine the size of the NULL terminiated string.
407 */
408 if (23 < temp16) {
409 temp8 = (u8) (temp16 - 24);
410 }
411 else {
412 temp8 = 0;
413 }
414
415 /*
416 * Ensure a 32-bit boundary for the structure
417 */
418 temp8 = (u8) ROUND_UP_TO_32_bITS (temp8);
419
420 structure_size = sizeof (ADDRESS32_RESOURCE) +
421 RESOURCE_LENGTH_NO_DATA +
422 (temp8 * sizeof (u8));
423 break;
424
425 case WORD_ADDRESS_SPACE:
426 /*
427 * 16-Bit Address Resource
428 */
429 buffer = byte_stream_buffer;
430
431 ++buffer;
432 MOVE_UNALIGNED16_TO_16 (&temp16, buffer);
433
434 bytes_consumed = temp16 + 3;
435
436 /*
437 * Resource Source Index and Resource Source are
438 * optional elements. Check the length of the
439 * Bytestream. If it is greater than 13, that
440 * means that an Index exists and is followed by
441 * a null termininated string. Therefore, set
442 * the temp variable to the length minus the minimum
443 * byte stream length plus the byte for the Index to
444 * determine the size of the NULL terminiated string.
445 */
446 if (13 < temp16) {
447 temp8 = (u8) (temp16 - 14);
448 }
449 else {
450 temp8 = 0;
451 }
452
453 /*
454 * Ensure a 32-bit boundry for the structure
455 */
456 temp8 = (u8) ROUND_UP_TO_32_bITS (temp8);
457
458 structure_size = sizeof (ADDRESS16_RESOURCE) +
459 RESOURCE_LENGTH_NO_DATA +
460 (temp8 * sizeof (u8));
461 break;
462
463 case EXTENDED_IRQ:
464 /*
465 * Extended IRQ
466 */
467 buffer = byte_stream_buffer;
468
469 ++buffer;
470 MOVE_UNALIGNED16_TO_16 (&temp16, buffer);
471
472 bytes_consumed = temp16 + 3;
473
474 /*
475 * Point past the length field and the
476 * Interrupt vector flags to save off the
477 * Interrupt table length to the Temp8 variable.
478 */
479 buffer += 3;
480 temp8 = *buffer;
481
482 /*
483 * To compensate for multiple interrupt numbers,
484 * Add 4 bytes for each additional interrupts
485 * greater than 1
486 */
487 additional_bytes = (u8) ((temp8 - 1) * 4);
488
489 /*
490 * Resource Source Index and Resource Source are
491 * optional elements. Check the length of the
492 * Bytestream. If it is greater than 9, that
493 * means that an Index exists and is followed by
494 * a null termininated string. Therefore, set
495 * the temp variable to the length minus the minimum
496 * byte stream length plus the byte for the Index to
497 * determine the size of the NULL terminiated string.
498 */
499 if (9 + additional_bytes < temp16) {
500 temp8 = (u8) (temp16 - (9 + additional_bytes));
501 }
502
503 else {
504 temp8 = 0;
505 }
506
507 /*
508 * Ensure a 32-bit boundry for the structure
509 */
510 temp8 = (u8) ROUND_UP_TO_32_bITS (temp8);
511
512 structure_size = sizeof (EXTENDED_IRQ_RESOURCE) +
513 RESOURCE_LENGTH_NO_DATA +
514 (additional_bytes * sizeof (u8)) +
515 (temp8 * sizeof (u8));
516
517 break;
518
519 /* TBD: [Future] 64-bit not currently supported */
520 /*
521 case 0x8A:
522 break;
523 */
524
525 default:
526 /*
527 * If we get here, everything is out of sync,
528 * so exit with an error
529 */
530 return (AE_AML_ERROR);
531 break;
532 }
533 }
534
535 else {
536 /*
537 * Small Resource Type
538 * Only bits 7:3 are valid
539 */
540 resource_type >>= 3;
541
542 switch (resource_type) {
543 case IRQ_FORMAT:
544 /*
545 * IRQ Resource
546 */
547 /*
548 * Determine if it there are two or three
549 * trailing bytes
550 */
551 buffer = byte_stream_buffer;
552 temp8 = *buffer;
553
554 if(temp8 & 0x01) {
555 bytes_consumed = 4;
556 }
557
558 else {
559 bytes_consumed = 3;
560 }
561
562 /*
563 * Point past the descriptor
564 */
565 ++buffer;
566
567 /*
568 * Look at the number of bits set
569 */
570 MOVE_UNALIGNED16_TO_16 (&temp16, buffer);
571
572 for (index = 0; index < 16; index++) {
573 if (temp16 & 0x1) {
574 ++number_of_interrupts;
575 }
576
577 temp16 >>= 1;
578 }
579
580 structure_size = sizeof (IO_RESOURCE) +
581 RESOURCE_LENGTH_NO_DATA +
582 (number_of_interrupts * sizeof (u32));
583 break;
584
585
586 case DMA_FORMAT:
587
588 /*
589 * DMA Resource
590 */
591 buffer = byte_stream_buffer;
592
593 bytes_consumed = 3;
594
595 /*
596 * Point past the descriptor
597 */
598 ++buffer;
599
600 /*
601 * Look at the number of bits set
602 */
603 temp8 = *buffer;
604
605 for(index = 0; index < 8; index++) {
606 if(temp8 & 0x1) {
607 ++number_of_channels;
608 }
609
610 temp8 >>= 1;
611 }
612
613 structure_size = sizeof (DMA_RESOURCE) +
614 RESOURCE_LENGTH_NO_DATA +
615 (number_of_channels * sizeof (u32));
616 break;
617
618
619 case START_DEPENDENT_TAG:
620
621 /*
622 * Start Dependent Functions Resource
623 */
624 /*
625 * Determine if it there are two or three trailing bytes
626 */
627 buffer = byte_stream_buffer;
628 temp8 = *buffer;
629
630 if(temp8 & 0x01) {
631 bytes_consumed = 2;
632 }
633 else {
634 bytes_consumed = 1;
635 }
636
637
638 structure_size =
639 sizeof (START_DEPENDENT_FUNCTIONS_RESOURCE) +
640 RESOURCE_LENGTH_NO_DATA;
641 break;
642
643
644 case END_DEPENDENT_TAG:
645
646 /*
647 * End Dependent Functions Resource
648 */
649 bytes_consumed = 1;
650 structure_size = RESOURCE_LENGTH;
651 break;
652
653
654 case IO_PORT_DESCRIPTOR:
655 /*
656 * IO Port Resource
657 */
658 bytes_consumed = 8;
659 structure_size = sizeof (IO_RESOURCE) +
660 RESOURCE_LENGTH_NO_DATA;
661 break;
662
663
664 case FIXED_LOCATION_IO_DESCRIPTOR:
665
666 /*
667 * Fixed IO Port Resource
668 */
669 bytes_consumed = 4;
670 structure_size = sizeof (FIXED_IO_RESOURCE) +
671 RESOURCE_LENGTH_NO_DATA;
672 break;
673
674
675 case SMALL_VENDOR_DEFINED:
676
677 /*
678 * Vendor Specific Resource
679 */
680 buffer = byte_stream_buffer;
681
682 temp8 = *buffer;
683 temp8 = (u8) (temp8 & 0x7);
684 bytes_consumed = temp8 + 1;
685
686 /*
687 * Ensure a 32-bit boundry for the structure
688 */
689 temp8 = (u8) ROUND_UP_TO_32_bITS (temp8);
690 structure_size = sizeof (VENDOR_RESOURCE) +
691 RESOURCE_LENGTH_NO_DATA +
692 (temp8 * sizeof (u8));
693 break;
694
695
696 case END_TAG:
697
698 /*
699 * End Tag
700 */
701 bytes_consumed = 2;
702 structure_size = RESOURCE_LENGTH;
703 byte_stream_buffer_length = bytes_parsed;
704 break;
705
706
707 default:
708 /*
709 * If we get here, everything is out of sync,
710 * so exit with an error
711 */
712 return (AE_AML_ERROR);
713 break;
714
715 } /* switch */
716
717 } /* if(Resource_type & 0x80) */
718
719 /*
720 * Update the return value and counter
721 */
722 buffer_size += structure_size;
723 bytes_parsed += bytes_consumed;
724
725 /*
726 * Set the byte stream to point to the next resource
727 */
728 byte_stream_buffer += bytes_consumed;
729
730 }
731
732 /*
733 * This is the data the caller needs
734 */
735 *size_needed = buffer_size;
736
737 return (AE_OK);
738 }
739
740
741 /*******************************************************************************
742 *
743 * FUNCTION: Acpi_rs_calculate_pci_routing_table_length
744 *
745 * PARAMETERS: Package_object - Pointer to the package object
746 * Buffer_size_needed - u32 pointer of the size buffer
747 * needed to properly return the
748 * parsed data
749 *
750 * RETURN: Status AE_OK
751 *
752 * DESCRIPTION: Given a package representing a PCI routing table, this
753 * calculates the size of the corresponding linked list of
754 * descriptions.
755 *
756 ******************************************************************************/
757
758 ACPI_STATUS
759 acpi_rs_calculate_pci_routing_table_length (
760 ACPI_OPERAND_OBJECT *package_object,
761 u32 *buffer_size_needed)
762 {
763 u32 number_of_elements;
764 u32 temp_size_needed = 0;
765 ACPI_OPERAND_OBJECT **top_object_list;
766 u32 index;
767 ACPI_OPERAND_OBJECT *package_element;
768 ACPI_OPERAND_OBJECT **sub_object_list;
769 u8 name_found;
770 u32 table_index;
771
772
773 number_of_elements = package_object->package.count;
774
775 /*
776 * Calculate the size of the return buffer.
777 * The base size is the number of elements * the sizes of the
778 * structures. Additional space for the strings is added below.
779 * The minus one is to subtract the size of the u8 Source[1]
780 * member because it is added below.
781 */
782
783 /*
784 * But each PRT_ENTRY structure has a pointer to a string and
785 * the size of that string must be found.
786 */
787 top_object_list = package_object->package.elements;
788
789 for (index = 0; index < number_of_elements; index++) {
790 /*
791 * Dereference the sub-package
792 */
793 package_element = *top_object_list;
794
795 /*
796 * The Sub_object_list will now point to an array of the
797 * four IRQ elements: Address, Pin, Source and Source_index
798 */
799 sub_object_list = package_element->package.elements;
800
801 /*
802 * Scan the Irq_table_elements for the Source Name String
803 */
804 name_found = FALSE;
805
806 for (table_index = 0; table_index < 4 && !name_found; table_index++) {
807 if ((ACPI_TYPE_STRING == (*sub_object_list)->common.type) ||
808 ((INTERNAL_TYPE_REFERENCE == (*sub_object_list)->common.type) &&
809 ((*sub_object_list)->reference.opcode == AML_NAMEPATH_OP))) {
810 name_found = TRUE;
811 }
812
813 else {
814 /*
815 * Look at the next element
816 */
817 sub_object_list++;
818 }
819 }
820
821 temp_size_needed += (sizeof (PCI_ROUTING_TABLE) - 4);
822
823 /*
824 * Was a String type found?
825 */
826 if (TRUE == name_found) {
827 if (ACPI_TYPE_STRING == (*sub_object_list)->common.type) {
828 /*
829 * The length String.Length field includes the
830 * terminating NULL
831 */
832 temp_size_needed += (*sub_object_list)->string.length;
833 }
834 else {
835 temp_size_needed += acpi_ns_get_pathname_length ((*sub_object_list)->reference.node);
836 }
837 }
838
839 else {
840 /*
841 * If no name was found, then this is a NULL, which is
842 * translated as a u32 zero.
843 */
844 temp_size_needed += sizeof(u32);
845 }
846
847
848 /* Round up the size since each element must be aligned */
849
850 temp_size_needed = ROUND_UP_TO_64_bITS (temp_size_needed);
851
852 /*
853 * Point to the next ACPI_OPERAND_OBJECT
854 */
855 top_object_list++;
856 }
857
858
859 /*
860 * Adding an extra element to the end of the list, essentially a NULL terminator
861 */
862 *buffer_size_needed = temp_size_needed + sizeof (PCI_ROUTING_TABLE);
863
864 return (AE_OK);
865 }