VirtualBox

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

Last change on this file since 75851 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

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