Save original PCI attributes in start() function and restore it in Stop().
[mirror_edk2.git] / OptionRomPkg / CirrusLogic5430Dxe / CirrusLogic5430GraphicsOutput.c
CommitLineData
87f8ccbe 1/*++\r
2\r
3Copyright (c) 2007, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 UefiCirrusLogic5430GraphicsOutput.c\r
15\r
16Abstract:\r
17\r
18 This file produces the graphics abstration of Graphics Output Protocol. It is called by \r
19 CirrusLogic5430.c file which deals with the EFI 1.1 driver model. \r
20 This file just does graphics.\r
21\r
22--*/\r
23\r
24#include "CirrusLogic5430.h"\r
25\r
26//\r
27// Graphics Output Protocol Member Functions\r
28//\r
29EFI_STATUS\r
30EFIAPI\r
31CirrusLogic5430GraphicsOutputQueryMode (\r
32 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,\r
33 IN UINT32 ModeNumber,\r
34 OUT UINTN *SizeOfInfo,\r
35 OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info\r
36 )\r
37/*++\r
38\r
39Routine Description:\r
40\r
41 Graphics Output protocol interface to query video mode\r
42\r
43 Arguments:\r
44 This - Protocol instance pointer.\r
45 ModeNumber - The mode number to return information on.\r
46 Info - Caller allocated buffer that returns information about ModeNumber.\r
47 SizeOfInfo - A pointer to the size, in bytes, of the Info buffer.\r
48\r
49 Returns:\r
50 EFI_SUCCESS - Mode information returned.\r
51 EFI_BUFFER_TOO_SMALL - The Info buffer was too small.\r
52 EFI_DEVICE_ERROR - A hardware error occurred trying to retrieve the video mode.\r
53 EFI_NOT_STARTED - Video display is not initialized. Call SetMode ()\r
54 EFI_INVALID_PARAMETER - One of the input args was NULL.\r
55\r
56--*/\r
57{\r
58 CIRRUS_LOGIC_5430_PRIVATE_DATA *Private;\r
59\r
60 Private = CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);\r
61\r
62 if (Private->HardwareNeedsStarting) {\r
63 return EFI_NOT_STARTED;\r
64 }\r
65\r
66 if (Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) {\r
67 return EFI_INVALID_PARAMETER;\r
68 }\r
69\r
70 *Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));\r
71 if (*Info == NULL) {\r
72 return EFI_OUT_OF_RESOURCES;\r
73 }\r
74\r
75 *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);\r
76\r
77 (*Info)->Version = 0;\r
78 (*Info)->HorizontalResolution = Private->ModeData[ModeNumber].HorizontalResolution;\r
79 (*Info)->VerticalResolution = Private->ModeData[ModeNumber].VerticalResolution;\r
80 (*Info)->PixelFormat = PixelBltOnly;\r
81 (*Info)->PixelsPerScanLine = (*Info)->HorizontalResolution;\r
82\r
83 return EFI_SUCCESS;\r
84}\r
85\r
86EFI_STATUS\r
87EFIAPI\r
88CirrusLogic5430GraphicsOutputSetMode (\r
89 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,\r
90 IN UINT32 ModeNumber\r
91 )\r
92/*++\r
93\r
94Routine Description:\r
95\r
96 Graphics Output protocol interface to set video mode\r
97\r
98 Arguments:\r
99 This - Protocol instance pointer.\r
100 ModeNumber - The mode number to be set.\r
101\r
102 Returns:\r
103 EFI_SUCCESS - Graphics mode was changed.\r
104 EFI_DEVICE_ERROR - The device had an error and could not complete the request.\r
105 EFI_UNSUPPORTED - ModeNumber is not supported by this device.\r
106\r
107--*/\r
108{\r
109 CIRRUS_LOGIC_5430_PRIVATE_DATA *Private;\r
110 CIRRUS_LOGIC_5430_MODE_DATA *ModeData;\r
111\r
112 Private = CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);\r
113\r
114 if (ModeNumber >= This->Mode->MaxMode) {\r
115 return EFI_UNSUPPORTED;\r
116 }\r
117\r
118 ModeData = &Private->ModeData[ModeNumber];\r
119\r
120 if (Private->LineBuffer) {\r
121 gBS->FreePool (Private->LineBuffer);\r
122 }\r
123\r
124 Private->LineBuffer = NULL;\r
125 Private->LineBuffer = AllocatePool (ModeData->HorizontalResolution);\r
126 if (Private->LineBuffer == NULL) {\r
127 return EFI_OUT_OF_RESOURCES;\r
128 }\r
129\r
130 InitializeGraphicsMode (Private, &CirrusLogic5430VideoModes[ModeNumber]);\r
131\r
132 This->Mode->Mode = ModeNumber;\r
133 This->Mode->Info->HorizontalResolution = ModeData->HorizontalResolution;\r
134 This->Mode->Info->VerticalResolution = ModeData->VerticalResolution;\r
135 This->Mode->Info->PixelFormat = PixelBltOnly;\r
136 This->Mode->Info->PixelsPerScanLine = ModeData->HorizontalResolution;\r
137 This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);\r
138\r
139 This->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS)(UINTN)NULL;\r
140 This->Mode->FrameBufferSize = 0;\r
141\r
142 Private->HardwareNeedsStarting = FALSE;\r
143\r
144 return EFI_SUCCESS;\r
145}\r
146\r
147EFI_STATUS\r
148EFIAPI\r
149CirrusLogic5430GraphicsOutputBlt (\r
150 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,\r
151 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL\r
152 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,\r
153 IN UINTN SourceX,\r
154 IN UINTN SourceY,\r
155 IN UINTN DestinationX,\r
156 IN UINTN DestinationY,\r
157 IN UINTN Width,\r
158 IN UINTN Height,\r
159 IN UINTN Delta\r
160 )\r
161/*++\r
162\r
163Routine Description:\r
164\r
165 Graphics Output protocol instance to block transfer for CirrusLogic device\r
166\r
167Arguments:\r
168\r
169 This - Pointer to Graphics Output protocol instance\r
170 BltBuffer - The data to transfer to screen\r
171 BltOperation - The operation to perform\r
172 SourceX - The X coordinate of the source for BltOperation\r
173 SourceY - The Y coordinate of the source for BltOperation\r
174 DestinationX - The X coordinate of the destination for BltOperation\r
175 DestinationY - The Y coordinate of the destination for BltOperation\r
176 Width - The width of a rectangle in the blt rectangle in pixels\r
177 Height - The height of a rectangle in the blt rectangle in pixels\r
178 Delta - Not used for EfiBltVideoFill and EfiBltVideoToVideo operation.\r
179 If a Delta of 0 is used, the entire BltBuffer will be operated on.\r
180 If a subrectangle of the BltBuffer is used, then Delta represents\r
181 the number of bytes in a row of the BltBuffer.\r
182\r
183Returns:\r
184\r
185 EFI_INVALID_PARAMETER - Invalid parameter passed in\r
186 EFI_SUCCESS - Blt operation success\r
187\r
188--*/\r
189{\r
190 CIRRUS_LOGIC_5430_PRIVATE_DATA *Private;\r
191 EFI_TPL OriginalTPL;\r
192 UINTN DstY;\r
193 UINTN SrcY;\r
194 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;\r
195 UINTN X;\r
196 UINT8 Pixel;\r
197 UINT32 WidePixel;\r
198 UINTN ScreenWidth;\r
199 UINTN Offset;\r
200 UINTN SourceOffset;\r
201 UINT32 CurrentMode;\r
202\r
203 Private = CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);\r
204\r
205 if ((BltOperation < 0) || (BltOperation >= EfiGraphicsOutputBltOperationMax)) {\r
206 return EFI_INVALID_PARAMETER;\r
207 }\r
208\r
209 if (Width == 0 || Height == 0) {\r
210 return EFI_INVALID_PARAMETER;\r
211 }\r
212\r
213 //\r
214 // If Delta is zero, then the entire BltBuffer is being used, so Delta\r
215 // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,\r
216 // the number of bytes in each row can be computed.\r
217 //\r
218 if (Delta == 0) {\r
219 Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);\r
220 }\r
221\r
222 //\r
223 // We need to fill the Virtual Screen buffer with the blt data.\r
224 // The virtual screen is upside down, as the first row is the bootom row of\r
225 // the image.\r
226 //\r
227\r
228 CurrentMode = This->Mode->Mode;\r
229 //\r
230 // Make sure the SourceX, SourceY, DestinationX, DestinationY, Width, and Height parameters\r
231 // are valid for the operation and the current screen geometry.\r
232 //\r
233 if (BltOperation == EfiBltVideoToBltBuffer) {\r
234 //\r
235 // Video to BltBuffer: Source is Video, destination is BltBuffer\r
236 //\r
237 if (SourceY + Height > Private->ModeData[CurrentMode].VerticalResolution) {\r
238 return EFI_INVALID_PARAMETER;\r
239 }\r
240\r
241 if (SourceX + Width > Private->ModeData[CurrentMode].HorizontalResolution) {\r
242 return EFI_INVALID_PARAMETER;\r
243 }\r
244 } else {\r
245 //\r
246 // BltBuffer to Video: Source is BltBuffer, destination is Video\r
247 //\r
248 if (DestinationY + Height > Private->ModeData[CurrentMode].VerticalResolution) {\r
249 return EFI_INVALID_PARAMETER;\r
250 }\r
251\r
252 if (DestinationX + Width > Private->ModeData[CurrentMode].HorizontalResolution) {\r
253 return EFI_INVALID_PARAMETER;\r
254 }\r
255 }\r
256 //\r
257 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.\r
258 // We would not want a timer based event (Cursor, ...) to come in while we are\r
259 // doing this operation.\r
260 //\r
261 OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);\r
262\r
263 switch (BltOperation) {\r
264 case EfiBltVideoToBltBuffer:\r
265 //\r
266 // Video to BltBuffer: Source is Video, destination is BltBuffer\r
267 //\r
268 for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) {\r
269\r
270 Offset = (SrcY * Private->ModeData[CurrentMode].HorizontalResolution) + SourceX;\r
271 if (((Offset & 0x03) == 0) && ((Width & 0x03) == 0)) {\r
272 Private->PciIo->Mem.Read (\r
273 Private->PciIo,\r
274 EfiPciIoWidthUint32,\r
275 0,\r
276 Offset,\r
277 Width >> 2,\r
278 Private->LineBuffer\r
279 );\r
280 } else {\r
281 Private->PciIo->Mem.Read (\r
282 Private->PciIo,\r
283 EfiPciIoWidthUint8,\r
284 0,\r
285 Offset,\r
286 Width,\r
287 Private->LineBuffer\r
288 );\r
289 }\r
290\r
291 for (X = 0; X < Width; X++) {\r
292 Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + (DstY * Delta) + (DestinationX + X) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
293\r
294 Blt->Red = (UINT8) (Private->LineBuffer[X] & 0xe0);\r
295 Blt->Green = (UINT8) ((Private->LineBuffer[X] & 0x1c) << 3);\r
296 Blt->Blue = (UINT8) ((Private->LineBuffer[X] & 0x03) << 6);\r
297 }\r
298 }\r
299 break;\r
300\r
301 case EfiBltVideoToVideo:\r
302 //\r
303 // Perform hardware acceleration for Video to Video operations\r
304 //\r
305 ScreenWidth = Private->ModeData[CurrentMode].HorizontalResolution;\r
306 SourceOffset = (SourceY * Private->ModeData[CurrentMode].HorizontalResolution) + (SourceX);\r
307 Offset = (DestinationY * Private->ModeData[CurrentMode].HorizontalResolution) + (DestinationX);\r
308\r
309 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0000);\r
310 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0010);\r
311 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0012);\r
312 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0014);\r
313\r
314 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0001);\r
315 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0011);\r
316 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0013);\r
317 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0015);\r
318\r
319 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) (((Width << 8) & 0xff00) | 0x20));\r
320 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((Width & 0xff00) | 0x21));\r
321 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) (((Height << 8) & 0xff00) | 0x22));\r
322 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((Height & 0xff00) | 0x23));\r
323 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) (((ScreenWidth << 8) & 0xff00) | 0x24));\r
324 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((ScreenWidth & 0xff00) | 0x25));\r
325 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) (((ScreenWidth << 8) & 0xff00) | 0x26));\r
326 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((ScreenWidth & 0xff00) | 0x27));\r
327 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((Offset) << 8) & 0xff00) | 0x28));\r
328 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((Offset) >> 0) & 0xff00) | 0x29));\r
329 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((Offset) >> 8) & 0xff00) | 0x2a));\r
330 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((SourceOffset) << 8) & 0xff00) | 0x2c));\r
331 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((SourceOffset) >> 0) & 0xff00) | 0x2d));\r
332 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((SourceOffset) >> 8) & 0xff00) | 0x2e));\r
333 outw (Private, GRAPH_ADDRESS_REGISTER, 0x002f);\r
334 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0030);\r
335 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0d32);\r
336 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0033);\r
337 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0034);\r
338 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0035);\r
339\r
340 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0231);\r
341\r
342 outb (Private, GRAPH_ADDRESS_REGISTER, 0x31);\r
343 while ((inb (Private, GRAPH_DATA_REGISTER) & 0x01) == 0x01)\r
344 ;\r
345 break;\r
346\r
347 case EfiBltVideoFill:\r
348 Blt = BltBuffer;\r
349 Pixel = (UINT8) ((Blt->Red & 0xe0) | ((Blt->Green >> 3) & 0x1c) | ((Blt->Blue >> 6) & 0x03));\r
350 WidePixel = (Pixel << 8) | Pixel;\r
351 WidePixel = (WidePixel << 16) | WidePixel;\r
352\r
353 if (DestinationX == 0 && Width == Private->ModeData[CurrentMode].HorizontalResolution) {\r
354 Offset = DestinationY * Private->ModeData[CurrentMode].HorizontalResolution;\r
355 if (((Offset & 0x03) == 0) && (((Width * Height) & 0x03) == 0)) {\r
356 Private->PciIo->Mem.Write (\r
357 Private->PciIo,\r
358 EfiPciIoWidthFillUint32,\r
359 0,\r
360 Offset,\r
361 (Width * Height) >> 2,\r
362 &WidePixel\r
363 );\r
364 } else {\r
365 Private->PciIo->Mem.Write (\r
366 Private->PciIo,\r
367 EfiPciIoWidthFillUint8,\r
368 0,\r
369 Offset,\r
370 Width * Height,\r
371 &Pixel\r
372 );\r
373 }\r
374 } else {\r
375 for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {\r
376 Offset = (DstY * Private->ModeData[CurrentMode].HorizontalResolution) + DestinationX;\r
377 if (((Offset & 0x03) == 0) && ((Width & 0x03) == 0)) {\r
378 Private->PciIo->Mem.Write (\r
379 Private->PciIo,\r
380 EfiPciIoWidthFillUint32,\r
381 0,\r
382 Offset,\r
383 Width >> 2,\r
384 &WidePixel\r
385 );\r
386 } else {\r
387 Private->PciIo->Mem.Write (\r
388 Private->PciIo,\r
389 EfiPciIoWidthFillUint8,\r
390 0,\r
391 Offset,\r
392 Width,\r
393 &Pixel\r
394 );\r
395 }\r
396 }\r
397 }\r
398 break;\r
399\r
400 case EfiBltBufferToVideo:\r
401 for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {\r
402\r
403 for (X = 0; X < Width; X++) {\r
404 Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + (SrcY * Delta) + (SourceX + X) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
405 Private->LineBuffer[X] = (UINT8) ((Blt->Red & 0xe0) | ((Blt->Green >> 3) & 0x1c) | ((Blt->Blue >> 6) & 0x03));\r
406 }\r
407\r
408 Offset = (DstY * Private->ModeData[CurrentMode].HorizontalResolution) + DestinationX;\r
409\r
410 if (((Offset & 0x03) == 0) && ((Width & 0x03) == 0)) {\r
411 Private->PciIo->Mem.Write (\r
412 Private->PciIo,\r
413 EfiPciIoWidthUint32,\r
414 0,\r
415 Offset,\r
416 Width >> 2,\r
417 Private->LineBuffer\r
418 );\r
419 } else {\r
420 Private->PciIo->Mem.Write (\r
421 Private->PciIo,\r
422 EfiPciIoWidthUint8,\r
423 0,\r
424 Offset,\r
425 Width,\r
426 Private->LineBuffer\r
427 );\r
428 }\r
429 }\r
430 break;\r
431 default:\r
432 ASSERT (FALSE);\r
433 }\r
434\r
435 gBS->RestoreTPL (OriginalTPL);\r
436\r
437 return EFI_SUCCESS;\r
438}\r
439\r
440EFI_STATUS\r
441CirrusLogic5430GraphicsOutputConstructor (\r
442 CIRRUS_LOGIC_5430_PRIVATE_DATA *Private\r
443 )\r
444{\r
445 EFI_STATUS Status;\r
446 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;\r
447 UINTN Index;\r
448\r
449\r
450 GraphicsOutput = &Private->GraphicsOutput;\r
451 GraphicsOutput->QueryMode = CirrusLogic5430GraphicsOutputQueryMode;\r
452 GraphicsOutput->SetMode = CirrusLogic5430GraphicsOutputSetMode;\r
453 GraphicsOutput->Blt = CirrusLogic5430GraphicsOutputBlt;\r
454\r
455 //\r
456 // Initialize the private data\r
457 //\r
458 Status = gBS->AllocatePool (\r
459 EfiBootServicesData,\r
460 sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE),\r
461 (VOID **) &Private->GraphicsOutput.Mode\r
462 );\r
463 if (EFI_ERROR (Status)) {\r
464 return Status;\r
465 }\r
466 Status = gBS->AllocatePool (\r
467 EfiBootServicesData,\r
468 sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION),\r
469 (VOID **) &Private->GraphicsOutput.Mode->Info\r
470 );\r
471 if (EFI_ERROR (Status)) {\r
472 return Status;\r
473 }\r
474 Private->GraphicsOutput.Mode->MaxMode = CIRRUS_LOGIC_5430_MODE_COUNT;\r
475 Private->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;\r
476 for (Index = 0; Index < Private->GraphicsOutput.Mode->MaxMode; Index++) {\r
477 Private->ModeData[Index].HorizontalResolution = CirrusLogic5430VideoModes[Index].Width;\r
478 Private->ModeData[Index].VerticalResolution = CirrusLogic5430VideoModes[Index].Height;\r
479 Private->ModeData[Index].ColorDepth = 32;\r
480 Private->ModeData[Index].RefreshRate = CirrusLogic5430VideoModes[Index].RefreshRate;\r
481 }\r
482\r
483 Private->HardwareNeedsStarting = TRUE;\r
484 Private->LineBuffer = NULL;\r
485\r
486 //\r
487 // Initialize the hardware\r
488 //\r
489 GraphicsOutput->SetMode (GraphicsOutput, 0);\r
490 DrawLogo (\r
491 Private,\r
492 Private->ModeData[Private->GraphicsOutput.Mode->Mode].HorizontalResolution,\r
493 Private->ModeData[Private->GraphicsOutput.Mode->Mode].VerticalResolution\r
494 );\r
495\r
496 return EFI_SUCCESS;\r
497}\r
498\r
499EFI_STATUS\r
500CirrusLogic5430GraphicsOutputDestructor (\r
501 CIRRUS_LOGIC_5430_PRIVATE_DATA *Private\r
502 )\r
503/*++\r
504\r
505Routine Description:\r
506\r
507Arguments:\r
508\r
509Returns:\r
510\r
511 None\r
512\r
513--*/\r
514{\r
515 if (Private->GraphicsOutput.Mode != NULL) {\r
516 if (Private->GraphicsOutput.Mode->Info != NULL) {\r
517 gBS->FreePool (Private->GraphicsOutput.Mode->Info);\r
518 }\r
519 gBS->FreePool (Private->GraphicsOutput.Mode);\r
520 }\r
521\r
522 return EFI_SUCCESS;\r
523}\r
524\r
525\r