]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/PlatformDxe/Platform.c
OvmfPkg: PlatformDxe: get available resolutions from GOP
[mirror_edk2.git] / OvmfPkg / PlatformDxe / Platform.c
CommitLineData
d945a8ba
LE
1/** @file\r
2 This driver effectuates OVMF's platform configuration settings and exposes\r
3 them via HII.\r
4\r
5 Copyright (C) 2014, Red Hat, Inc.\r
bc4c5366 6 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
d945a8ba
LE
7\r
8 This program and the accompanying materials are licensed and made available\r
9 under the terms and conditions of the BSD License which accompanies this\r
10 distribution. The full text of the license may be found at\r
11 http://opensource.org/licenses/bsd-license.php\r
12\r
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
14 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
15**/\r
16\r
92e74550 17#include <Library/BaseLib.h>\r
d945a8ba 18#include <Library/DebugLib.h>\r
877a4dbb
LE
19#include <Library/DevicePathLib.h>\r
20#include <Library/HiiLib.h>\r
da07afaf
LE
21#include <Library/MemoryAllocationLib.h>\r
22#include <Library/PrintLib.h>\r
d945a8ba 23#include <Library/UefiBootServicesTableLib.h>\r
92e74550 24#include <Library/UefiHiiServicesLib.h>\r
877a4dbb 25#include <Protocol/DevicePath.h>\r
da07afaf 26#include <Protocol/GraphicsOutput.h>\r
877a4dbb 27#include <Protocol/HiiConfigAccess.h>\r
92e74550
LE
28#include <Guid/MdeModuleHii.h>\r
29#include <Guid/OvmfPlatformConfig.h>\r
d945a8ba 30\r
92e74550 31#include "Platform.h"\r
bdaf30e4
LE
32#include "PlatformConfig.h"\r
33\r
877a4dbb
LE
34//\r
35// The HiiAddPackages() library function requires that any controller (or\r
36// image) handle, to be associated with the HII packages under installation, be\r
37// "decorated" with a device path. The tradition seems to be a vendor device\r
38// path.\r
39//\r
40// We'd like to associate our HII packages with the driver's image handle. The\r
41// first idea is to use the driver image's device path. Unfortunately, loaded\r
42// images only come with an EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL (not the\r
43// usual EFI_DEVICE_PATH_PROTOCOL), ie. a different GUID. In addition, even the\r
44// EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL interface may be NULL, if the image\r
45// has been loaded from an "unnamed" memory source buffer.\r
46//\r
47// Hence let's just stick with the tradition -- use a dedicated vendor device\r
48// path, with the driver's FILE_GUID.\r
49//\r
50#pragma pack(1)\r
51typedef struct {\r
52 VENDOR_DEVICE_PATH VendorDevicePath;\r
53 EFI_DEVICE_PATH_PROTOCOL End;\r
54} PKG_DEVICE_PATH;\r
55#pragma pack()\r
56\r
57STATIC PKG_DEVICE_PATH mPkgDevicePath = {\r
58 {\r
59 {\r
60 HARDWARE_DEVICE_PATH,\r
61 HW_VENDOR_DP,\r
62 {\r
63 (UINT8) (sizeof (VENDOR_DEVICE_PATH) ),\r
64 (UINT8) (sizeof (VENDOR_DEVICE_PATH) >> 8)\r
65 }\r
66 },\r
67 EFI_CALLER_ID_GUID\r
68 },\r
69 {\r
70 END_DEVICE_PATH_TYPE,\r
71 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
72 {\r
73 (UINT8) (END_DEVICE_PATH_LENGTH ),\r
74 (UINT8) (END_DEVICE_PATH_LENGTH >> 8)\r
75 }\r
76 }\r
77};\r
78\r
79//\r
80// The configuration interface between the HII engine (form display etc) and\r
81// this driver.\r
82//\r
83STATIC EFI_HII_CONFIG_ACCESS_PROTOCOL mConfigAccess;\r
84\r
85//\r
86// The handle representing our list of packages after installation.\r
87//\r
88STATIC EFI_HII_HANDLE mInstalledPackages;\r
89\r
90//\r
91// The arrays below constitute our HII package list. They are auto-generated by\r
92// the VFR compiler and linked into the driver image during the build.\r
93//\r
94// - The strings package receives its C identifier from the driver's BASE_NAME,\r
95// plus "Strings".\r
96//\r
97// - The forms package receives its C identifier from the VFR file's basename,\r
98// plus "Bin".\r
99//\r
100//\r
101extern UINT8 PlatformDxeStrings[];\r
102extern UINT8 PlatformFormsBin[];\r
103\r
da07afaf
LE
104//\r
105// We want to be notified about GOP installations until we find one GOP\r
106// interface that lets us populate the form.\r
107//\r
108STATIC EFI_EVENT mGopEvent;\r
109\r
110//\r
111// The registration record underneath this pointer allows us to iterate through\r
112// the GOP instances one by one.\r
113//\r
114STATIC VOID *mGopTracker;\r
115\r
116//\r
117// Cache the resolutions we get from the GOP.\r
118//\r
119typedef struct {\r
120 UINT32 X;\r
121 UINT32 Y;\r
122} GOP_MODE;\r
123\r
124STATIC UINTN mNumGopModes;\r
125STATIC GOP_MODE *mGopModes;\r
126\r
877a4dbb 127\r
92e74550
LE
128/**\r
129 This function is called by the HII machinery when it fetches the form state.\r
130\r
131 See the precise documentation in the UEFI spec.\r
132\r
133 @param[in] This The Config Access Protocol instance.\r
134\r
135 @param[in] Request A <ConfigRequest> format UCS-2 string describing the\r
136 query.\r
137\r
138 @param[out] Progress A pointer into Request on output, identifying the query\r
139 element where processing failed.\r
140\r
141 @param[out] Results A <MultiConfigAltResp> format UCS-2 string that has\r
142 all values filled in for the names in the Request\r
143 string.\r
144\r
145 @return Status codes from gHiiConfigRouting->BlockToConfig().\r
146\r
147**/\r
877a4dbb
LE
148STATIC\r
149EFI_STATUS\r
150EFIAPI\r
151ExtractConfig (\r
152 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
153 IN CONST EFI_STRING Request,\r
154 OUT EFI_STRING *Progress,\r
155 OUT EFI_STRING *Results\r
156)\r
157{\r
92e74550
LE
158 MAIN_FORM_STATE MainFormState;\r
159 EFI_STATUS Status;\r
160\r
161 DEBUG ((EFI_D_VERBOSE, "%a: Request=\"%s\"\n", __FUNCTION__, Request));\r
162\r
163 StrnCpy ((CHAR16 *) MainFormState.CurrentPreferredResolution,\r
164 L"Unset", MAXSIZE_RES_CUR);\r
165 MainFormState.NextPreferredResolution = 0;\r
166 Status = gHiiConfigRouting->BlockToConfig (gHiiConfigRouting, Request,\r
167 (VOID *) &MainFormState, sizeof MainFormState,\r
168 Results, Progress);\r
169 if (EFI_ERROR (Status)) {\r
170 DEBUG ((EFI_D_ERROR, "%a: BlockToConfig(): %r, Progress=\"%s\"\n",\r
171 __FUNCTION__, Status, (Status == EFI_DEVICE_ERROR) ? NULL : *Progress));\r
172 } else {\r
173 DEBUG ((EFI_D_VERBOSE, "%a: Results=\"%s\"\n", __FUNCTION__, *Results));\r
174 }\r
175 return Status;\r
877a4dbb
LE
176}\r
177\r
178\r
179STATIC\r
180EFI_STATUS\r
181EFIAPI\r
182RouteConfig (\r
183 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
184 IN CONST EFI_STRING Configuration,\r
185 OUT EFI_STRING *Progress\r
186)\r
187{\r
188 return EFI_SUCCESS;\r
189}\r
190\r
191\r
192STATIC\r
193EFI_STATUS\r
194EFIAPI\r
195Callback (\r
196 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
197 IN EFI_BROWSER_ACTION Action,\r
198 IN EFI_QUESTION_ID QuestionId,\r
199 IN UINT8 Type,\r
200 IN OUT EFI_IFR_TYPE_VALUE *Value,\r
201 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest\r
202 )\r
203{\r
204 return EFI_SUCCESS;\r
205}\r
206\r
207\r
da07afaf
LE
208/**\r
209 Query and save all resolutions supported by the GOP.\r
210\r
211 @param[in] Gop The Graphics Output Protocol instance to query.\r
212\r
213 @param[out] NumGopModes The number of modes supported by the GOP. On output,\r
214 this parameter will be positive.\r
215\r
216 @param[out] GopModes On output, a dynamically allocated array containing\r
217 the resolutions returned by the GOP. The caller is\r
218 responsible for freeing the array after use.\r
219\r
220 @retval EFI_UNSUPPORTED No modes found.\r
221 @retval EFI_OUT_OF_RESOURCES Failed to allocate GopModes.\r
222 @return Error codes from Gop->QueryMode().\r
223\r
224**/\r
225STATIC\r
226EFI_STATUS\r
227EFIAPI\r
228QueryGopModes (\r
229 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop,\r
230 OUT UINTN *NumGopModes,\r
231 OUT GOP_MODE **GopModes\r
232 )\r
233{\r
234 EFI_STATUS Status;\r
235 UINT32 ModeNumber;\r
236\r
237 if (Gop->Mode->MaxMode == 0) {\r
238 return EFI_UNSUPPORTED;\r
239 }\r
240 *NumGopModes = Gop->Mode->MaxMode;\r
241\r
242 *GopModes = AllocatePool (Gop->Mode->MaxMode * sizeof **GopModes);\r
243 if (*GopModes == NULL) {\r
244 return EFI_OUT_OF_RESOURCES;\r
245 }\r
246\r
247 for (ModeNumber = 0; ModeNumber < Gop->Mode->MaxMode; ++ModeNumber) {\r
248 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;\r
249 UINTN SizeOfInfo;\r
250\r
251 Status = Gop->QueryMode (Gop, ModeNumber, &SizeOfInfo, &Info);\r
252 if (EFI_ERROR (Status)) {\r
253 goto FreeGopModes;\r
254 }\r
255\r
256 (*GopModes)[ModeNumber].X = Info->HorizontalResolution;\r
257 (*GopModes)[ModeNumber].Y = Info->VerticalResolution;\r
258 FreePool (Info);\r
259 }\r
260\r
261 return EFI_SUCCESS;\r
262\r
263FreeGopModes:\r
264 FreePool (*GopModes);\r
265\r
266 return Status;\r
267}\r
268\r
269\r
92e74550
LE
270/**\r
271 Create a set of "one-of-many" (ie. "drop down list") option IFR opcodes,\r
272 based on available GOP resolutions, to be placed under a "one-of-many" (ie.\r
273 "drop down list") opcode.\r
274\r
275 @param[in] PackageList The package list with the formset and form for\r
276 which the drop down options are produced. Option\r
277 names are added as new strings to PackageList.\r
278\r
279 @param[out] OpCodeBuffer On output, a dynamically allocated opcode buffer\r
280 with drop down list options corresponding to GOP\r
281 resolutions. The caller is responsible for freeing\r
282 OpCodeBuffer with HiiFreeOpCodeHandle() after use.\r
283\r
da07afaf
LE
284 @param[in] NumGopModes Number of entries in GopModes.\r
285\r
286 @param[in] GopModes Array of resolutions retrieved from the GOP.\r
287\r
92e74550
LE
288 @retval EFI_SUCESS Opcodes have been successfully produced.\r
289\r
290 @return Status codes from underlying functions. PackageList may\r
291 have been extended with new strings. OpCodeBuffer is\r
292 unchanged.\r
293**/\r
294STATIC\r
295EFI_STATUS\r
296EFIAPI\r
297CreateResolutionOptions (\r
298 IN EFI_HII_HANDLE *PackageList,\r
da07afaf
LE
299 OUT VOID **OpCodeBuffer,\r
300 IN UINTN NumGopModes,\r
301 IN GOP_MODE *GopModes\r
92e74550
LE
302 )\r
303{\r
da07afaf
LE
304 EFI_STATUS Status;\r
305 VOID *OutputBuffer;\r
306 UINTN ModeNumber;\r
92e74550
LE
307\r
308 OutputBuffer = HiiAllocateOpCodeHandle ();\r
309 if (OutputBuffer == NULL) {\r
310 return EFI_OUT_OF_RESOURCES;\r
311 }\r
312\r
da07afaf
LE
313 for (ModeNumber = 0; ModeNumber < NumGopModes; ++ModeNumber) {\r
314 CHAR16 Desc[MAXSIZE_RES_CUR];\r
315 EFI_STRING_ID NewString;\r
316 VOID *OpCode;\r
317\r
318 UnicodeSPrintAsciiFormat (Desc, sizeof Desc, "%Ldx%Ld",\r
319 (INT64) GopModes[ModeNumber].X, (INT64) GopModes[ModeNumber].Y);\r
320 NewString = HiiSetString (PackageList, 0 /* new string */, Desc,\r
321 NULL /* for all languages */);\r
322 if (NewString == 0) {\r
323 Status = EFI_OUT_OF_RESOURCES;\r
324 goto FreeOutputBuffer;\r
325 }\r
326 OpCode = HiiCreateOneOfOptionOpCode (OutputBuffer, NewString,\r
327 0 /* Flags */, EFI_IFR_NUMERIC_SIZE_4, ModeNumber);\r
328 if (OpCode == NULL) {\r
329 Status = EFI_OUT_OF_RESOURCES;\r
330 goto FreeOutputBuffer;\r
331 }\r
92e74550
LE
332 }\r
333\r
334 *OpCodeBuffer = OutputBuffer;\r
335 return EFI_SUCCESS;\r
336\r
337FreeOutputBuffer:\r
338 HiiFreeOpCodeHandle (OutputBuffer);\r
339\r
340 return Status;\r
341}\r
342\r
343\r
344/**\r
345 Populate the form identified by the (PackageList, FormSetGuid, FormId)\r
346 triplet.\r
347\r
da07afaf
LE
348 The drop down list of video resolutions is generated from (NumGopModes,\r
349 GopModes).\r
350\r
92e74550
LE
351 @retval EFI_SUCESS Form successfully updated.\r
352 @return Status codes from underlying functions.\r
353\r
354**/\r
355STATIC\r
356EFI_STATUS\r
357EFIAPI\r
358PopulateForm (\r
359 IN EFI_HII_HANDLE *PackageList,\r
360 IN EFI_GUID *FormSetGuid,\r
da07afaf
LE
361 IN EFI_FORM_ID FormId,\r
362 IN UINTN NumGopModes,\r
363 IN GOP_MODE *GopModes\r
92e74550
LE
364 )\r
365{\r
366 EFI_STATUS Status;\r
367 VOID *OpCodeBuffer;\r
368 VOID *OpCode;\r
369 EFI_IFR_GUID_LABEL *Anchor;\r
370 VOID *OpCodeBuffer2;\r
371\r
bc4c5366
JJ
372 OpCodeBuffer2 = NULL;\r
373\r
92e74550
LE
374 //\r
375 // 1. Allocate an empty opcode buffer.\r
376 //\r
377 OpCodeBuffer = HiiAllocateOpCodeHandle ();\r
378 if (OpCodeBuffer == NULL) {\r
379 return EFI_OUT_OF_RESOURCES;\r
380 }\r
381\r
382 //\r
383 // 2. Create a label opcode (which is a Tiano extension) inside the buffer.\r
384 // The label's number must match the "anchor" label in the form.\r
385 //\r
386 OpCode = HiiCreateGuidOpCode (OpCodeBuffer, &gEfiIfrTianoGuid,\r
387 NULL /* optional copy origin */, sizeof *Anchor);\r
388 if (OpCode == NULL) {\r
389 Status = EFI_OUT_OF_RESOURCES;\r
390 goto FreeOpCodeBuffer;\r
391 }\r
392 Anchor = OpCode;\r
393 Anchor->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
394 Anchor->Number = LABEL_RES_NEXT;\r
395\r
396 //\r
397 // 3. Create the opcodes inside the buffer that are to be inserted into the\r
398 // form.\r
399 //\r
400 // 3.1. Get a list of resolutions.\r
401 //\r
da07afaf
LE
402 Status = CreateResolutionOptions (PackageList, &OpCodeBuffer2,\r
403 NumGopModes, GopModes);\r
92e74550
LE
404 if (EFI_ERROR (Status)) {\r
405 goto FreeOpCodeBuffer;\r
406 }\r
407\r
408 //\r
409 // 3.2. Create a one-of-many question with the above options.\r
410 //\r
411 OpCode = HiiCreateOneOfOpCode (\r
412 OpCodeBuffer, // create opcode inside this\r
413 // opcode buffer,\r
414 QUESTION_RES_NEXT, // ID of question,\r
415 FORMSTATEID_MAIN_FORM, // identifies form state\r
416 // storage,\r
417 (UINT16) OFFSET_OF (MAIN_FORM_STATE, // value of question stored\r
418 NextPreferredResolution), // at this offset,\r
419 STRING_TOKEN (STR_RES_NEXT), // Prompt,\r
420 STRING_TOKEN (STR_RES_NEXT_HELP), // Help,\r
421 0, // QuestionFlags,\r
422 EFI_IFR_NUMERIC_SIZE_4, // see sizeof\r
423 // NextPreferredResolution,\r
424 OpCodeBuffer2, // buffer with possible\r
425 // choices,\r
426 NULL // DEFAULT opcodes\r
427 );\r
428 if (OpCode == NULL) {\r
429 Status = EFI_OUT_OF_RESOURCES;\r
430 goto FreeOpCodeBuffer2;\r
431 }\r
432\r
433 //\r
434 // 4. Update the form with the opcode buffer.\r
435 //\r
436 Status = HiiUpdateForm (PackageList, FormSetGuid, FormId,\r
437 OpCodeBuffer, // buffer with head anchor, and new contents to be\r
438 // inserted at it\r
439 NULL // buffer with tail anchor, for deleting old\r
440 // contents up to it\r
441 );\r
442\r
443FreeOpCodeBuffer2:\r
444 HiiFreeOpCodeHandle (OpCodeBuffer2);\r
445\r
446FreeOpCodeBuffer:\r
447 HiiFreeOpCodeHandle (OpCodeBuffer);\r
448\r
449 return Status;\r
450}\r
451\r
452\r
bdaf30e4
LE
453/**\r
454 Load and execute the platform configuration.\r
455\r
456 @retval EFI_SUCCESS Configuration loaded and executed.\r
457 @return Status codes from PlatformConfigLoad().\r
458**/\r
459STATIC\r
460EFI_STATUS\r
461EFIAPI\r
462ExecutePlatformConfig (\r
463 VOID\r
464 )\r
465{\r
466 EFI_STATUS Status;\r
467 PLATFORM_CONFIG PlatformConfig;\r
468 UINT64 OptionalElements;\r
469\r
470 Status = PlatformConfigLoad (&PlatformConfig, &OptionalElements);\r
471 if (EFI_ERROR (Status)) {\r
472 DEBUG (((Status == EFI_NOT_FOUND) ? EFI_D_VERBOSE : EFI_D_ERROR,\r
473 "%a: failed to load platform config: %r\n", __FUNCTION__, Status));\r
474 return Status;\r
475 }\r
476\r
477 if (OptionalElements & PLATFORM_CONFIG_F_GRAPHICS_RESOLUTION) {\r
478 //\r
479 // Pass the preferred resolution to GraphicsConsoleDxe via dynamic PCDs.\r
480 //\r
481 PcdSet32 (PcdVideoHorizontalResolution,\r
482 PlatformConfig.HorizontalResolution);\r
483 PcdSet32 (PcdVideoVerticalResolution,\r
484 PlatformConfig.VerticalResolution);\r
485 }\r
486\r
487 return EFI_SUCCESS;\r
488}\r
489\r
490\r
da07afaf
LE
491/**\r
492 Notification callback for GOP interface installation.\r
493\r
494 @param[in] Event Event whose notification function is being invoked.\r
495\r
496 @param[in] Context The pointer to the notification function's context, which\r
497 is implementation-dependent.\r
498**/\r
499STATIC\r
500VOID\r
501EFIAPI\r
502GopInstalled (\r
503 IN EFI_EVENT Event,\r
504 IN VOID *Context\r
505 )\r
506{\r
507 EFI_STATUS Status;\r
508 EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;\r
509\r
510 ASSERT (Event == mGopEvent);\r
511\r
512 //\r
513 // Check further GOPs.\r
514 //\r
515 for (;;) {\r
516 mNumGopModes = 0;\r
517 mGopModes = NULL;\r
518\r
519 Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, mGopTracker,\r
520 (VOID **) &Gop);\r
521 if (EFI_ERROR (Status)) {\r
522 return;\r
523 }\r
524\r
525 Status = QueryGopModes (Gop, &mNumGopModes, &mGopModes);\r
526 if (EFI_ERROR (Status)) {\r
527 continue;\r
528 }\r
529\r
530 Status = PopulateForm (mInstalledPackages, &gOvmfPlatformConfigGuid,\r
531 FORMID_MAIN_FORM, mNumGopModes, mGopModes);\r
532 if (EFI_ERROR (Status)) {\r
533 FreePool (mGopModes);\r
534 continue;\r
535 }\r
536\r
537 break;\r
538 }\r
539\r
540 //\r
541 // Success -- so uninstall this callback. Closing the event removes all\r
542 // pending notifications and all protocol registrations.\r
543 //\r
544 Status = gBS->CloseEvent (mGopEvent);\r
545 ASSERT_EFI_ERROR (Status);\r
546 mGopEvent = NULL;\r
547 mGopTracker = NULL;\r
548}\r
549\r
550\r
d945a8ba
LE
551/**\r
552 Entry point for this driver.\r
553\r
554 @param[in] ImageHandle Image handle of this driver.\r
555 @param[in] SystemTable Pointer to SystemTable.\r
556\r
557 @retval EFI_SUCESS Driver has loaded successfully.\r
877a4dbb
LE
558 @retval EFI_OUT_OF_RESOURCES Failed to install HII packages.\r
559 @return Error codes from lower level functions.\r
d945a8ba
LE
560\r
561**/\r
562EFI_STATUS\r
563EFIAPI\r
564PlatformInit (\r
565 IN EFI_HANDLE ImageHandle,\r
566 IN EFI_SYSTEM_TABLE *SystemTable\r
567 )\r
568{\r
877a4dbb
LE
569 EFI_STATUS Status;\r
570\r
bdaf30e4 571 ExecutePlatformConfig ();\r
877a4dbb
LE
572\r
573 mConfigAccess.ExtractConfig = &ExtractConfig;\r
574 mConfigAccess.RouteConfig = &RouteConfig;\r
575 mConfigAccess.Callback = &Callback;\r
576\r
577 //\r
578 // Declare ourselves suitable for HII communication.\r
579 //\r
580 Status = gBS->InstallMultipleProtocolInterfaces (&ImageHandle,\r
581 &gEfiDevicePathProtocolGuid, &mPkgDevicePath,\r
582 &gEfiHiiConfigAccessProtocolGuid, &mConfigAccess,\r
583 NULL);\r
584 if (EFI_ERROR (Status)) {\r
585 return Status;\r
586 }\r
587\r
588 //\r
589 // Publish the HII package list to HII Database.\r
590 //\r
591 mInstalledPackages = HiiAddPackages (\r
592 &gEfiCallerIdGuid, // PackageListGuid\r
593 ImageHandle, // associated DeviceHandle\r
594 PlatformDxeStrings, // 1st package\r
595 PlatformFormsBin, // 2nd package\r
596 NULL // terminator\r
597 );\r
598 if (mInstalledPackages == NULL) {\r
599 Status = EFI_OUT_OF_RESOURCES;\r
600 goto UninstallProtocols;\r
601 }\r
602\r
da07afaf
LE
603 Status = gBS->CreateEvent (EVT_NOTIFY_SIGNAL, TPL_CALLBACK, &GopInstalled,\r
604 NULL /* Context */, &mGopEvent);\r
92e74550
LE
605 if (EFI_ERROR (Status)) {\r
606 goto RemovePackages;\r
607 }\r
608\r
da07afaf
LE
609 Status = gBS->RegisterProtocolNotify (&gEfiGraphicsOutputProtocolGuid,\r
610 mGopEvent, &mGopTracker);\r
611 if (EFI_ERROR (Status)) {\r
612 goto CloseGopEvent;\r
613 }\r
614\r
615 //\r
616 // Check already installed GOPs.\r
617 //\r
618 Status = gBS->SignalEvent (mGopEvent);\r
619 ASSERT_EFI_ERROR (Status);\r
620\r
d945a8ba 621 return EFI_SUCCESS;\r
877a4dbb 622\r
da07afaf
LE
623CloseGopEvent:\r
624 gBS->CloseEvent (mGopEvent);\r
625\r
92e74550
LE
626RemovePackages:\r
627 HiiRemovePackages (mInstalledPackages);\r
628\r
877a4dbb
LE
629UninstallProtocols:\r
630 gBS->UninstallMultipleProtocolInterfaces (ImageHandle,\r
631 &gEfiDevicePathProtocolGuid, &mPkgDevicePath,\r
632 &gEfiHiiConfigAccessProtocolGuid, &mConfigAccess,\r
633 NULL);\r
634 return Status;\r
d945a8ba
LE
635}\r
636\r
637/**\r
638 Unload the driver.\r
639\r
640 @param[in] ImageHandle Handle that identifies the image to evict.\r
641\r
642 @retval EFI_SUCCESS The image has been unloaded.\r
643**/\r
644EFI_STATUS\r
645EFIAPI\r
646PlatformUnload (\r
647 IN EFI_HANDLE ImageHandle\r
648 )\r
649{\r
da07afaf
LE
650 if (mGopEvent == NULL) {\r
651 //\r
652 // The GOP callback ran successfully and unregistered itself. Release the\r
653 // resources allocated there.\r
654 //\r
655 ASSERT (mGopModes != NULL);\r
656 FreePool (mGopModes);\r
657 } else {\r
658 //\r
659 // Otherwise we need to unregister the callback.\r
660 //\r
661 ASSERT (mGopModes == NULL);\r
662 gBS->CloseEvent (mGopEvent);\r
663 }\r
664\r
665 //\r
666 // Release resources allocated by the entry point.\r
667 //\r
877a4dbb
LE
668 HiiRemovePackages (mInstalledPackages);\r
669 gBS->UninstallMultipleProtocolInterfaces (ImageHandle,\r
670 &gEfiDevicePathProtocolGuid, &mPkgDevicePath,\r
671 &gEfiHiiConfigAccessProtocolGuid, &mConfigAccess,\r
672 NULL);\r
d945a8ba
LE
673 return EFI_SUCCESS;\r
674}\r