VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/Edid.c

Last change on this file was 106061, checked in by vboxsync, 4 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.8 KB
Line 
1/* $Id: Edid.c 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * Edid.c
4 */
5
6/*
7 * Copyright (C) 2009-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * 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, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37/*
38 This code is based on:
39
40 Read EDID information and parse EDID information.
41
42 Copyright (c) 2008, Intel Corporation
43 All rights reserved. This program and the accompanying materials
44 are licensed and made available under the terms and conditions of the BSD License
45 which accompanies this distribution. The full text of the license may be found at
46 http://opensource.org/licenses/bsd-license.php
47
48 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
49 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
50
51*/
52
53#include "VBoxVga.h"
54#include "VBoxVgaI2c.h"
55
56//
57// EDID block
58//
59typedef struct {
60 UINT8 Header[8]; //EDID header "00 FF FF FF FF FF FF 00"
61 UINT16 ManufactureName; //EISA 3-character ID
62 UINT16 ProductCode; //Vendor assigned code
63 UINT32 SerialNumber; //32-bit serial number
64 UINT8 WeekOfManufacture; //Week number
65 UINT8 YearOfManufacture; //Year
66 UINT8 EdidVersion; //EDID Structure Version
67 UINT8 EdidRevision; //EDID Structure Revision
68 UINT8 VideoInputDefinition;
69 UINT8 MaxHorizontalImageSize; //cm
70 UINT8 MaxVerticalImageSize; //cm
71 UINT8 DisplayTransferCharacteristic;
72 UINT8 FeatureSupport;
73 UINT8 RedGreenLowBits; //Rx1 Rx0 Ry1 Ry0 Gx1 Gx0 Gy1Gy0
74 UINT8 BlueWhiteLowBits; //Bx1 Bx0 By1 By0 Wx1 Wx0 Wy1 Wy0
75 UINT8 RedX; //Red-x Bits 9 - 2
76 UINT8 RedY; //Red-y Bits 9 - 2
77 UINT8 GreenX; //Green-x Bits 9 - 2
78 UINT8 GreenY; //Green-y Bits 9 - 2
79 UINT8 BlueX; //Blue-x Bits 9 - 2
80 UINT8 BlueY; //Blue-y Bits 9 - 2
81 UINT8 WhiteX; //White-x Bits 9 - 2
82 UINT8 WhiteY; //White-x Bits 9 - 2
83 UINT8 EstablishedTimings[3];
84 UINT8 StandardTimingIdentification[16];
85 UINT8 DetailedTimingDescriptions[72];
86 UINT8 ExtensionFlag; //Number of (optional) 128-byte EDID extension blocks to follow
87 UINT8 Checksum;
88} EDID_BLOCK;
89
90#define EDID_BLOCK_SIZE 128
91#define VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER 17
92
93typedef struct {
94 UINT16 HorizontalResolution;
95 UINT16 VerticalResolution;
96 UINT16 RefreshRate;
97} EDID_TIMING;
98
99typedef struct {
100 UINT32 ValidNumber;
101 UINT32 Key[VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER];
102} VALID_EDID_TIMING;
103
104//
105// Standard timing defined by VESA EDID
106//
107EDID_TIMING mVbeEstablishedEdidTiming[] = {
108 //
109 // Established Timing I
110 //
111 {800, 600, 60},
112 {800, 600, 56},
113 {640, 480, 75},
114 {640, 480, 72},
115 {640, 480, 67},
116 {640, 480, 60},
117 {720, 400, 88},
118 {720, 400, 70},
119 //
120 // Established Timing II
121 //
122 {1280, 1024, 75},
123 {1024, 768, 75},
124 {1024, 768, 70},
125 {1024, 768, 60},
126 {1024, 768, 87},
127 {832, 624, 75},
128 {800, 600, 75},
129 {800, 600, 72},
130 //
131 // Established Timing III
132 //
133 {1152, 870, 75}
134};
135
136/**
137 Read EDID information from I2C Bus on CirrusLogic.
138
139 @param Private Pointer to VBOX_VGA_PRIVATE_DATA.
140 @param EdidDataBlock Pointer to EDID data block.
141 @param EdidSize Returned EDID block size.
142
143 @retval EFI_UNSUPPORTED
144 @retval EFI_SUCCESS
145
146**/
147EFI_STATUS
148ReadEdidData (
149 VBOX_VGA_PRIVATE_DATA *Private,
150 UINT8 **EdidDataBlock,
151 UINTN *EdidSize
152 )
153{
154 UINTN Index;
155 UINT8 EdidData[EDID_BLOCK_SIZE * 2];
156 UINT8 *ValidEdid;
157 UINT64 Signature;
158
159 for (Index = 0; Index < EDID_BLOCK_SIZE * 2; Index ++) {
160 I2cReadByte (Private->PciIo, 0xa0, (UINT8)Index, &EdidData[Index]);
161 }
162
163 //
164 // Search for the EDID signature
165 //
166 ValidEdid = &EdidData[0];
167 Signature = 0x00ffffffffffff00ull;
168 for (Index = 0; Index < EDID_BLOCK_SIZE * 2; Index ++, ValidEdid ++) {
169 if (CompareMem (ValidEdid, &Signature, 8) == 0) {
170 break;
171 }
172 }
173
174 if (Index == 256) {
175 //
176 // No EDID signature found
177 //
178 return EFI_UNSUPPORTED;
179 }
180
181 *EdidDataBlock = AllocateCopyPool (
182 sizeof (EDID_BLOCK_SIZE),
183 ValidEdid
184 );
185 if (*EdidDataBlock == NULL) {
186 return EFI_OUT_OF_RESOURCES;
187 }
188
189 //
190 // Currently only support EDID 1.x
191 //
192 *EdidSize = EDID_BLOCK_SIZE;
193
194 return EFI_SUCCESS;
195}
196
197/**
198 Generate a search key for a specified timing data.
199
200 @param EdidTiming Pointer to EDID timing
201
202 @return The 32 bit unique key for search.
203
204**/
205UINT32
206CalculateEdidKey (
207 EDID_TIMING *EdidTiming
208 )
209{
210 UINT32 Key;
211
212 //
213 // Be sure no conflicts for all standard timing defined by VESA.
214 //
215 Key = (EdidTiming->HorizontalResolution * 2) + EdidTiming->VerticalResolution;
216 return Key;
217}
218
219/**
220 Search a specified Timing in all the valid EDID timings.
221
222 @param ValidEdidTiming All valid EDID timing information.
223 @param EdidTiming The Timing to search for.
224
225 @retval TRUE Found.
226 @retval FALSE Not found.
227
228**/
229BOOLEAN
230SearchEdidTiming (
231 VALID_EDID_TIMING *ValidEdidTiming,
232 EDID_TIMING *EdidTiming
233 )
234{
235 UINT32 Index;
236 UINT32 Key;
237
238 Key = CalculateEdidKey (EdidTiming);
239
240 for (Index = 0; Index < ValidEdidTiming->ValidNumber; Index ++) {
241 if (Key == ValidEdidTiming->Key[Index]) {
242 return TRUE;
243 }
244 }
245
246 return FALSE;
247}
248
249/**
250 Parse the Established Timing and Standard Timing in EDID data block.
251
252 @param EdidBuffer Pointer to EDID data block
253 @param ValidEdidTiming Valid EDID timing information
254
255 @retval TRUE The EDID data is valid.
256 @retval FALSE The EDID data is invalid.
257
258**/
259BOOLEAN
260ParseEdidData (
261 UINT8 *EdidBuffer,
262 VALID_EDID_TIMING *ValidEdidTiming
263 )
264{
265 UINT8 CheckSum;
266 UINT32 Index;
267 UINT32 ValidNumber;
268 UINT32 TimingBits;
269 UINT8 *BufferIndex;
270 UINT16 HorizontalResolution;
271 UINT16 VerticalResolution;
272 UINT8 AspectRatio;
273 UINT8 RefreshRate;
274 EDID_TIMING TempTiming;
275 EDID_BLOCK *EdidDataBlock;
276
277 EdidDataBlock = (EDID_BLOCK *) EdidBuffer;
278
279 //
280 // Check the checksum of EDID data
281 //
282 CheckSum = 0;
283 for (Index = 0; Index < EDID_BLOCK_SIZE; Index ++) {
284 CheckSum = (UINT8) (CheckSum + EdidBuffer[Index]);
285 }
286 if (CheckSum != 0) {
287 return FALSE;
288 }
289
290 ValidNumber = 0;
291 SetMem (ValidEdidTiming, sizeof (VALID_EDID_TIMING), 0);
292
293 if ((EdidDataBlock->EstablishedTimings[0] != 0) ||
294 (EdidDataBlock->EstablishedTimings[1] != 0) ||
295 (EdidDataBlock->EstablishedTimings[2] != 0)
296 ) {
297 //
298 // Established timing data
299 //
300 TimingBits = EdidDataBlock->EstablishedTimings[0] |
301 (EdidDataBlock->EstablishedTimings[1] << 8) |
302 ((EdidDataBlock->EstablishedTimings[2] & 0x80) << 9) ;
303 for (Index = 0; Index < VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER; Index ++) {
304 if (TimingBits & 0x1) {
305 ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&mVbeEstablishedEdidTiming[Index]);
306 ValidNumber ++;
307 }
308 TimingBits = TimingBits >> 1;
309 }
310 } else {
311 //
312 // If no Established timing data, read the standard timing data
313 //
314 BufferIndex = &EdidDataBlock->StandardTimingIdentification[0];
315 for (Index = 0; Index < 8; Index ++) {
316 if ((BufferIndex[0] != 0x1) && (BufferIndex[1] != 0x1)){
317 //
318 // A valid Standard Timing
319 //
320 HorizontalResolution = (UINT16) (BufferIndex[0] * 8 + 248);
321 AspectRatio = (UINT8) (BufferIndex[1] >> 6);
322 switch (AspectRatio) {
323 case 0:
324 VerticalResolution = (UINT16) (HorizontalResolution / 16 * 10);
325 break;
326 case 1:
327 VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);
328 break;
329 case 2:
330 VerticalResolution = (UINT16) (HorizontalResolution / 5 * 4);
331 break;
332 case 3:
333 VerticalResolution = (UINT16) (HorizontalResolution / 16 * 9);
334 break;
335 default:
336 VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);
337 break;
338 }
339 RefreshRate = (UINT8) ((BufferIndex[1] & 0x1f) + 60);
340 TempTiming.HorizontalResolution = HorizontalResolution;
341 TempTiming.VerticalResolution = VerticalResolution;
342 TempTiming.RefreshRate = RefreshRate;
343 ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&TempTiming);
344 ValidNumber ++;
345 }
346 BufferIndex += 2;
347 }
348 }
349
350 ValidEdidTiming->ValidNumber = ValidNumber;
351 return TRUE;
352}
353
354static uint16_t in_word(uint16_t port, uint16_t addr)
355{
356 ASMOutU16(port, addr);
357 return ASMInU16(port);
358}
359
360static EFI_STATUS VBoxVgaVideoModeInitExtra(void)
361{
362 UINT16 w, cur_info_ofs, vmode, xres, yres;
363 UINTN Index;
364 VBOX_VGA_VIDEO_MODES *VideoMode;
365
366 // Read and check the VBE Extra Data magic
367 w = in_word(VBE_EXTRA_PORT, 0);
368 if (w != VBEHEADER_MAGIC) {
369 DEBUG((DEBUG_INFO, "%a:%d could not find VBE magic, got %x\n", __FILE__, __LINE__, w));
370 return EFI_NOT_FOUND;
371 }
372
373 cur_info_ofs = sizeof(VBEHeader);
374
375 Index = VBoxVgaVideoModeCount - 16;
376 VideoMode = &VBoxVgaVideoModes[Index];
377 vmode = in_word(VBE_EXTRA_PORT, cur_info_ofs + OFFSET_OF(ModeInfoListItem, mode));
378 while (vmode != VBE_VESA_MODE_END_OF_LIST)
379 {
380 xres = in_word(VBE_EXTRA_PORT, cur_info_ofs + OFFSET_OF(ModeInfoListItem, info.XResolution));
381 yres = in_word(VBE_EXTRA_PORT, cur_info_ofs + OFFSET_OF(ModeInfoListItem, info.YResolution));
382
383 if (vmode >= VBE_VBOX_MODE_CUSTOM1 && vmode <= VBE_VBOX_MODE_CUSTOM16 && xres && yres && Index < VBoxVgaVideoModeCount) {
384 VideoMode->Width = xres;
385 VideoMode->Height = yres;
386 VideoMode->ColorDepth = 32;
387 VideoMode->RefreshRate = 60;
388 VideoMode->MiscSetting = 0x01;
389 VideoMode++;
390 Index++;
391 }
392
393 cur_info_ofs += sizeof(ModeInfoListItem);
394 vmode = in_word(VBE_EXTRA_PORT, cur_info_ofs + OFFSET_OF(ModeInfoListItem, mode));
395 }
396 return EFI_SUCCESS;
397}
398
399/**
400 Construct the valid video modes for VBoxVga.
401
402**/
403EFI_STATUS
404VBoxVgaVideoModeSetup (
405 VBOX_VGA_PRIVATE_DATA *Private
406 )
407{
408 EFI_STATUS Status;
409 UINT32 Index;
410 BOOLEAN EdidFound;
411 EFI_EDID_OVERRIDE_PROTOCOL *EdidOverride;
412 UINT32 EdidAttributes;
413 BOOLEAN EdidOverrideFound;
414 UINTN EdidOverrideDataSize;
415 UINT8 *EdidOverrideDataBlock;
416 UINTN EdidDiscoveredDataSize;
417 UINT8 *EdidDiscoveredDataBlock;
418 UINTN EdidActiveDataSize;
419 UINT8 *EdidActiveDataBlock;
420 VALID_EDID_TIMING ValidEdidTiming;
421 UINT32 ValidModeCount;
422 VBOX_VGA_MODE_DATA *ModeData;
423 BOOLEAN TimingMatch;
424 const VBOX_VGA_VIDEO_MODES *VideoMode;
425 EDID_TIMING TempTiming;
426
427 //
428 // setup EDID information
429 //
430 Private->EdidDiscovered.Edid = NULL;
431 Private->EdidDiscovered.SizeOfEdid = 0;
432 Private->EdidActive.Edid = NULL;
433 Private->EdidActive.SizeOfEdid = 0;
434
435 EdidFound = FALSE;
436 EdidOverrideFound = FALSE;
437 EdidAttributes = 0xff;
438 EdidOverrideDataSize = 0;
439 EdidOverrideDataBlock = NULL;
440 EdidActiveDataSize = 0;
441 EdidActiveDataBlock = NULL;
442 EdidDiscoveredDataBlock = NULL;
443
444 //
445 // Find EDID Override protocol firstly, this protocol is installed by platform if needed.
446 //
447 Status = gBS->LocateProtocol (
448 &gEfiEdidOverrideProtocolGuid,
449 NULL,
450 (VOID **) &EdidOverride
451 );
452 if (!EFI_ERROR (Status)) {
453 //
454 // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow
455 //
456 EdidOverrideDataBlock = AllocatePool (sizeof (EDID_BLOCK_SIZE * 2));
457 if (NULL == EdidOverrideDataBlock) {
458 Status = EFI_OUT_OF_RESOURCES;
459 goto Done;
460 }
461
462 Status = EdidOverride->GetEdid (
463 EdidOverride,
464 Private->Handle,
465 &EdidAttributes,
466 &EdidOverrideDataSize,
467 (UINT8 **) &EdidOverrideDataBlock
468 );
469 if (!EFI_ERROR (Status) &&
470 EdidAttributes == 0 &&
471 EdidOverrideDataSize != 0) {
472 //
473 // Succeeded to get EDID Override Data
474 //
475 EdidOverrideFound = TRUE;
476 }
477 }
478
479 if (EdidOverrideFound != TRUE || EdidAttributes == EFI_EDID_OVERRIDE_DONT_OVERRIDE) {
480 //
481 // If EDID Override data doesn't exist or EFI_EDID_OVERRIDE_DONT_OVERRIDE returned,
482 // read EDID information through I2C Bus
483 //
484 if (ReadEdidData (Private, &EdidDiscoveredDataBlock, &EdidDiscoveredDataSize) == EFI_SUCCESS) {
485 Private->EdidDiscovered.SizeOfEdid = (UINT32) EdidDiscoveredDataSize;
486 Private->EdidDiscovered.Edid = (UINT8 *) AllocateCopyPool (
487 EdidDiscoveredDataSize,
488 EdidDiscoveredDataBlock
489 );
490
491 if (NULL == Private->EdidDiscovered.Edid) {
492 Status = EFI_OUT_OF_RESOURCES;
493 goto Done;
494 }
495
496 EdidActiveDataSize = Private->EdidDiscovered.SizeOfEdid;
497 EdidActiveDataBlock = Private->EdidDiscovered.Edid;
498
499 EdidFound = TRUE;
500 }
501 }
502
503 if (EdidFound != TRUE && EdidOverrideFound == TRUE) {
504 EdidActiveDataSize = EdidOverrideDataSize;
505 EdidActiveDataBlock = EdidOverrideDataBlock;
506 EdidFound = TRUE;
507 }
508
509 if (EdidFound == TRUE) {
510 //
511 // Parse EDID data structure to retrieve modes supported by monitor
512 //
513 if (ParseEdidData ((UINT8 *) EdidActiveDataBlock, &ValidEdidTiming) == TRUE) {
514 //
515 // Copy EDID Override Data to EDID Active Data
516 //
517 Private->EdidActive.SizeOfEdid = (UINT32) EdidActiveDataSize;
518 Private->EdidActive.Edid = (UINT8 *) AllocateCopyPool (
519 EdidActiveDataSize,
520 EdidActiveDataBlock
521 );
522 if (NULL == Private->EdidActive.Edid) {
523 Status = EFI_OUT_OF_RESOURCES;
524 goto Done;
525 }
526 }
527 } else {
528 Private->EdidActive.SizeOfEdid = 0;
529 Private->EdidActive.Edid = NULL;
530 EdidFound = FALSE;
531 }
532
533 if (EdidFound && 0) {
534 //
535 // Initialize the private mode data with the supported modes.
536 //
537 ValidModeCount = 0;
538 Private->ModeData = AllocatePool(sizeof(VBOX_VGA_MODE_DATA) * VBoxVgaVideoModeCount);
539 ModeData = &Private->ModeData[0];
540 VideoMode = &VBoxVgaVideoModes[0];
541 for (Index = 0; Index < VBoxVgaVideoModeCount; Index++) {
542
543 TimingMatch = TRUE;
544
545 //
546 // Check whether match with VBoxVga video mode
547 //
548 TempTiming.HorizontalResolution = (UINT16) VideoMode->Width;
549 TempTiming.VerticalResolution = (UINT16) VideoMode->Height;
550 TempTiming.RefreshRate = (UINT16) VideoMode->RefreshRate;
551 if (SearchEdidTiming (&ValidEdidTiming, &TempTiming) != TRUE) {
552 TimingMatch = FALSE;
553 }
554
555 //
556 // Not export Mode 0x0 as GOP mode, this is not defined in spec.
557 //
558 if ((VideoMode->Width == 0) || (VideoMode->Height == 0)) {
559 TimingMatch = FALSE;
560 }
561
562 //
563 // Check whether the mode would be exceeding the VRAM size.
564 //
565 if (VideoMode->Width * VideoMode->Height * (VideoMode->ColorDepth / 8) > Private->VRAMSize) {
566 TimingMatch = FALSE;
567 }
568
569 if (TimingMatch) {
570 ModeData->ModeNumber = Index;
571 ModeData->HorizontalResolution = VideoMode->Width;
572 ModeData->VerticalResolution = VideoMode->Height;
573 ModeData->ColorDepth = VideoMode->ColorDepth;
574 ModeData->RefreshRate = VideoMode->RefreshRate;
575
576 ModeData ++;
577 ValidModeCount ++;
578 }
579
580 VideoMode ++;
581 }
582 } else {
583 //
584 // If EDID information wasn't found
585 //
586 VBoxVgaVideoModeInitExtra();
587 ValidModeCount = 0;
588 Private->ModeData = AllocatePool(sizeof(VBOX_VGA_MODE_DATA) * VBoxVgaVideoModeCount);
589 ModeData = &Private->ModeData[0];
590 VideoMode = &VBoxVgaVideoModes[0];
591 for (Index = 0; Index < VBoxVgaVideoModeCount; Index ++) {
592
593 TimingMatch = TRUE;
594
595 //
596 // Not export Mode 0x0 as GOP mode, this is not defined in spec.
597 //
598 if ((VideoMode->Width == 0) || (VideoMode->Height == 0)) {
599 TimingMatch = FALSE;
600 }
601
602 //
603 // Check whether the mode would be exceeding the VRAM size.
604 //
605 if (VideoMode->Width * VideoMode->Height * (VideoMode->ColorDepth / 8) > Private->VRAMSize) {
606 TimingMatch = FALSE;
607 }
608
609 if (TimingMatch) {
610 ModeData->ModeNumber = Index;
611 ModeData->HorizontalResolution = VideoMode->Width;
612 ModeData->VerticalResolution = VideoMode->Height;
613 ModeData->ColorDepth = VideoMode->ColorDepth;
614 ModeData->RefreshRate = VideoMode->RefreshRate;
615
616 ModeData ++;
617 ValidModeCount ++;
618 }
619
620 VideoMode ++;
621 }
622 }
623
624 // Sort list of video modes (keeping duplicates) by increasing X, then Y,
625 // then the mode number. This way the custom modes are not overriding the
626 // default modes if they are for the same resolution.
627 ModeData = &Private->ModeData[0];
628 for (Index = 0; Index < ValidModeCount - 1; Index ++) {
629 UINT32 Index2;
630 VBOX_VGA_MODE_DATA *ModeData2 = ModeData + 1;
631 for (Index2 = Index + 1; Index2 < ValidModeCount; Index2 ++) {
632 if ( ModeData->HorizontalResolution > ModeData2->HorizontalResolution
633 || ( ModeData->HorizontalResolution == ModeData2->HorizontalResolution
634 && ModeData->VerticalResolution > ModeData2->VerticalResolution)
635 || ( ModeData->HorizontalResolution == ModeData2->HorizontalResolution
636 && ModeData->VerticalResolution == ModeData2->VerticalResolution
637 && ModeData->ModeNumber > ModeData2->ModeNumber)) {
638 VBOX_VGA_MODE_DATA Tmp;
639 CopyMem(&Tmp, ModeData, sizeof(Tmp));
640 CopyMem(ModeData, ModeData2, sizeof(Tmp));
641 CopyMem(ModeData2, &Tmp, sizeof(Tmp));
642 DEBUG((DEBUG_INFO, "%a:%d swapped mode entries %d and %d\n", __FILE__, __LINE__, Index, Index2));
643 }
644 ModeData2++;
645 }
646 ModeData++;
647 }
648
649 // dump mode list for debugging purposes
650 ModeData = &Private->ModeData[0];
651 for (Index = 0; Index < ValidModeCount; Index ++) {
652 DEBUG((DEBUG_INFO, "%a:%d mode %d: %dx%d mode number %d\n", __FILE__, __LINE__, Index, ModeData->HorizontalResolution, ModeData->VerticalResolution, ModeData->ModeNumber));
653 ModeData++;
654 }
655
656 Private->MaxMode = ValidModeCount;
657
658 if (EdidOverrideDataBlock != NULL) {
659 FreePool (EdidOverrideDataBlock);
660 }
661
662 return EFI_SUCCESS;
663
664Done:
665 if (EdidOverrideDataBlock != NULL) {
666 FreePool (EdidOverrideDataBlock);
667 }
668 if (Private->EdidDiscovered.Edid != NULL) {
669 FreePool (Private->EdidDiscovered.Edid);
670 }
671 if (Private->EdidDiscovered.Edid != NULL) {
672 FreePool (Private->EdidActive.Edid);
673 }
674
675 return EFI_DEVICE_ERROR;
676}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette