]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Application/UiApp/FrontPageCustomizedUiSupport.c
MdeModulePkg/UiApp: Retrieve the value of language menu
[mirror_edk2.git] / MdeModulePkg / Application / UiApp / FrontPageCustomizedUiSupport.c
1 /** @file
2
3 This library class defines a set of interfaces to customize Ui module
4
5 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials are licensed and made available under
7 the terms and conditions of the BSD License that accompanies this distribution.
8 The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15 #include <Uefi.h>
16
17 #include <Guid/MdeModuleHii.h>
18 #include <Guid/GlobalVariable.h>
19
20 #include <Protocol/HiiConfigAccess.h>
21 #include <Protocol/HiiString.h>
22
23 #include <Library/HiiLib.h>
24 #include <Library/DebugLib.h>
25 #include <Library/UefiLib.h>
26 #include <Library/BaseMemoryLib.h>
27 #include <Library/PcdLib.h>
28 #include <Library/MemoryAllocationLib.h>
29 #include <Library/UefiRuntimeServicesTableLib.h>
30 #include <Library/UefiHiiServicesLib.h>
31 #include <Library/DevicePathLib.h>
32 #include <Library/UefiBootServicesTableLib.h>
33 #include "FrontPageCustomizedUiSupport.h"
34
35 //
36 // This is the VFR compiler generated header file which defines the
37 // string identifiers.
38 //
39 #define PRINTABLE_LANGUAGE_NAME_STRING_ID 0x0001
40
41 #define UI_HII_DRIVER_LIST_SIZE 0x8
42
43 #define FRONT_PAGE_KEY_CONTINUE 0x1000
44 #define FRONT_PAGE_KEY_RESET 0x1001
45 #define FRONT_PAGE_KEY_LANGUAGE 0x1002
46
47 typedef struct {
48 EFI_STRING_ID PromptId;
49 EFI_STRING_ID HelpId;
50 EFI_STRING_ID DevicePathId;
51 EFI_GUID FormSetGuid;
52 BOOLEAN EmptyLineAfter;
53 } UI_HII_DRIVER_INSTANCE;
54
55 CHAR8 *gLanguageString;
56 EFI_STRING_ID *gLanguageToken;
57 UI_HII_DRIVER_INSTANCE *gHiiDriverList;
58 extern EFI_HII_HANDLE gStringPackHandle;
59 UINT8 gCurrentLanguageIndex;
60
61
62 /**
63 Get next language from language code list (with separator ';').
64
65 If LangCode is NULL, then ASSERT.
66 If Lang is NULL, then ASSERT.
67
68 @param LangCode On input: point to first language in the list. On
69 output: point to next language in the list, or
70 NULL if no more language in the list.
71 @param Lang The first language in the list.
72
73 **/
74 VOID
75 GetNextLanguage (
76 IN OUT CHAR8 **LangCode,
77 OUT CHAR8 *Lang
78 )
79 {
80 UINTN Index;
81 CHAR8 *StringPtr;
82
83 ASSERT (LangCode != NULL);
84 ASSERT (*LangCode != NULL);
85 ASSERT (Lang != NULL);
86
87 Index = 0;
88 StringPtr = *LangCode;
89 while (StringPtr[Index] != 0 && StringPtr[Index] != ';') {
90 Index++;
91 }
92
93 CopyMem (Lang, StringPtr, Index);
94 Lang[Index] = 0;
95
96 if (StringPtr[Index] == ';') {
97 Index++;
98 }
99 *LangCode = StringPtr + Index;
100 }
101
102 /**
103 This function processes the language changes in configuration.
104
105 @param Value A pointer to the data being sent to the original exporting driver.
106
107
108 @retval TRUE The callback successfully handled the action.
109 @retval FALSE The callback not supported in this handler.
110
111 **/
112 EFI_STATUS
113 LanguageChangeHandler (
114 IN EFI_IFR_TYPE_VALUE *Value
115 )
116 {
117 CHAR8 *LangCode;
118 CHAR8 *Lang;
119 UINTN Index;
120 EFI_STATUS Status;
121
122 //
123 // Allocate working buffer for RFC 4646 language in supported LanguageString.
124 //
125 Lang = AllocatePool (AsciiStrSize (gLanguageString));
126 ASSERT (Lang != NULL);
127
128 Index = 0;
129 LangCode = gLanguageString;
130 while (*LangCode != 0) {
131 GetNextLanguage (&LangCode, Lang);
132
133 if (Index == Value->u8) {
134 gCurrentLanguageIndex = Value->u8;
135 break;
136 }
137
138 Index++;
139 }
140
141 if (Index == Value->u8) {
142 Status = gRT->SetVariable (
143 L"PlatformLang",
144 &gEfiGlobalVariableGuid,
145 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
146 AsciiStrSize (Lang),
147 Lang
148 );
149 if (EFI_ERROR (Status)) {
150 FreePool (Lang);
151 return EFI_DEVICE_ERROR;
152 }
153 } else {
154 ASSERT (FALSE);
155 }
156 FreePool (Lang);
157
158 return EFI_SUCCESS;
159 }
160
161 /**
162 This function processes the results of changes in configuration.
163
164
165 @param HiiHandle Points to the hii handle for this formset.
166 @param Action Specifies the type of action taken by the browser.
167 @param QuestionId A unique value which is sent to the original exporting driver
168 so that it can identify the type of data to expect.
169 @param Type The type of value for the question.
170 @param Value A pointer to the data being sent to the original exporting driver.
171 @param ActionRequest On return, points to the action requested by the callback function.
172 @param Status Return the handle status.
173
174 @retval TRUE The callback successfully handled the action.
175 @retval FALSE The callback not supported in this handler.
176
177 **/
178 BOOLEAN
179 UiSupportLibCallbackHandler (
180 IN EFI_HII_HANDLE HiiHandle,
181 IN EFI_BROWSER_ACTION Action,
182 IN EFI_QUESTION_ID QuestionId,
183 IN UINT8 Type,
184 IN EFI_IFR_TYPE_VALUE *Value,
185 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest,
186 OUT EFI_STATUS *Status
187 )
188 {
189 if (QuestionId != FRONT_PAGE_KEY_CONTINUE &&
190 QuestionId != FRONT_PAGE_KEY_RESET &&
191 QuestionId != FRONT_PAGE_KEY_LANGUAGE) {
192 return FALSE;
193 }
194
195 if (Action == EFI_BROWSER_ACTION_RETRIEVE) {
196 if (QuestionId == FRONT_PAGE_KEY_LANGUAGE) {
197 Value->u8 = gCurrentLanguageIndex;
198 *Status = EFI_SUCCESS;
199 } else {
200 *Status = EFI_UNSUPPORTED;
201 }
202 return TRUE;
203 }
204
205 if (Action != EFI_BROWSER_ACTION_CHANGED) {
206 //
207 // Do nothing for other UEFI Action. Only do call back when data is changed.
208 //
209 *Status = EFI_UNSUPPORTED;
210 return TRUE;
211 }
212
213 if (Action == EFI_BROWSER_ACTION_CHANGED) {
214 if ((Value == NULL) || (ActionRequest == NULL)) {
215 *Status = EFI_INVALID_PARAMETER;
216 return TRUE;
217 }
218
219 *Status = EFI_SUCCESS;
220 switch (QuestionId) {
221 case FRONT_PAGE_KEY_CONTINUE:
222 //
223 // This is the continue - clear the screen and return an error to get out of FrontPage loop
224 //
225 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
226 break;
227
228 case FRONT_PAGE_KEY_LANGUAGE:
229 *Status = LanguageChangeHandler(Value);
230 break;
231
232 case FRONT_PAGE_KEY_RESET:
233 //
234 // Reset
235 //
236 gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
237 *Status = EFI_UNSUPPORTED;
238
239 default:
240 break;
241 }
242 }
243
244 return TRUE;
245 }
246
247 /**
248 Create Select language menu in the front page with oneof opcode.
249
250 @param[in] HiiHandle The hii handle for the Uiapp driver.
251 @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
252
253 **/
254 VOID
255 UiCreateLanguageMenu (
256 IN EFI_HII_HANDLE HiiHandle,
257 IN VOID *StartOpCodeHandle
258 )
259 {
260 CHAR8 *LangCode;
261 CHAR8 *Lang;
262 CHAR8 *CurrentLang;
263 UINTN OptionCount;
264 CHAR16 *StringBuffer;
265 VOID *OptionsOpCodeHandle;
266 UINTN StringSize;
267 EFI_STATUS Status;
268 EFI_HII_STRING_PROTOCOL *HiiString;
269
270 Lang = NULL;
271 StringBuffer = NULL;
272
273 //
274 // Init OpCode Handle and Allocate space for creation of UpdateData Buffer
275 //
276 OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
277 ASSERT (OptionsOpCodeHandle != NULL);
278
279 GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&CurrentLang, NULL);
280
281 //
282 // Get Support language list from variable.
283 //
284 GetEfiGlobalVariable2 (L"PlatformLangCodes", (VOID**)&gLanguageString, NULL);
285 if (gLanguageString == NULL) {
286 gLanguageString = AllocateCopyPool (
287 AsciiStrSize ((CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes)),
288 (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes)
289 );
290 ASSERT (gLanguageString != NULL);
291 }
292
293 if (gLanguageToken == NULL) {
294 //
295 // Count the language list number.
296 //
297 LangCode = gLanguageString;
298 Lang = AllocatePool (AsciiStrSize (gLanguageString));
299 ASSERT (Lang != NULL);
300
301 OptionCount = 0;
302 while (*LangCode != 0) {
303 GetNextLanguage (&LangCode, Lang);
304 OptionCount ++;
305 }
306
307 //
308 // Allocate extra 1 as the end tag.
309 //
310 gLanguageToken = AllocateZeroPool ((OptionCount + 1) * sizeof (EFI_STRING_ID));
311 ASSERT (gLanguageToken != NULL);
312
313 Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &HiiString);
314 ASSERT_EFI_ERROR (Status);
315
316 LangCode = gLanguageString;
317 OptionCount = 0;
318 while (*LangCode != 0) {
319 GetNextLanguage (&LangCode, Lang);
320
321 StringSize = 0;
322 Status = HiiString->GetString (HiiString, Lang, HiiHandle, PRINTABLE_LANGUAGE_NAME_STRING_ID, StringBuffer, &StringSize, NULL);
323 if (Status == EFI_BUFFER_TOO_SMALL) {
324 StringBuffer = AllocateZeroPool (StringSize);
325 ASSERT (StringBuffer != NULL);
326 Status = HiiString->GetString (HiiString, Lang, HiiHandle, PRINTABLE_LANGUAGE_NAME_STRING_ID, StringBuffer, &StringSize, NULL);
327 ASSERT_EFI_ERROR (Status);
328 }
329
330 if (EFI_ERROR (Status)) {
331 StringBuffer = AllocatePool (AsciiStrSize (Lang) * sizeof (CHAR16));
332 ASSERT (StringBuffer != NULL);
333 AsciiStrToUnicodeStr (Lang, StringBuffer);
334 }
335
336 ASSERT (StringBuffer != NULL);
337 gLanguageToken[OptionCount] = HiiSetString (HiiHandle, 0, StringBuffer, NULL);
338 FreePool (StringBuffer);
339
340 OptionCount++;
341 }
342 }
343
344 ASSERT (gLanguageToken != NULL);
345 LangCode = gLanguageString;
346 OptionCount = 0;
347 if (Lang == NULL) {
348 Lang = AllocatePool (AsciiStrSize (gLanguageString));
349 ASSERT (Lang != NULL);
350 }
351 while (*LangCode != 0) {
352 GetNextLanguage (&LangCode, Lang);
353
354 if (CurrentLang != NULL && AsciiStrCmp (Lang, CurrentLang) == 0) {
355 HiiCreateOneOfOptionOpCode (
356 OptionsOpCodeHandle,
357 gLanguageToken[OptionCount],
358 EFI_IFR_OPTION_DEFAULT,
359 EFI_IFR_NUMERIC_SIZE_1,
360 (UINT8) OptionCount
361 );
362 gCurrentLanguageIndex = (UINT8) OptionCount;
363 } else {
364 HiiCreateOneOfOptionOpCode (
365 OptionsOpCodeHandle,
366 gLanguageToken[OptionCount],
367 0,
368 EFI_IFR_NUMERIC_SIZE_1,
369 (UINT8) OptionCount
370 );
371 }
372
373 OptionCount++;
374 }
375
376 if (CurrentLang != NULL) {
377 FreePool (CurrentLang);
378 }
379 FreePool (Lang);
380
381 HiiCreateOneOfOpCode (
382 StartOpCodeHandle,
383 FRONT_PAGE_KEY_LANGUAGE,
384 0,
385 0,
386 STRING_TOKEN (STR_LANGUAGE_SELECT),
387 STRING_TOKEN (STR_LANGUAGE_SELECT_HELP),
388 EFI_IFR_FLAG_CALLBACK,
389 EFI_IFR_NUMERIC_SIZE_1,
390 OptionsOpCodeHandle,
391 NULL
392 );
393 }
394
395 /**
396 Create continue menu in the front page.
397
398 @param[in] HiiHandle The hii handle for the Uiapp driver.
399 @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
400
401 **/
402 VOID
403 UiCreateContinueMenu (
404 IN EFI_HII_HANDLE HiiHandle,
405 IN VOID *StartOpCodeHandle
406 )
407 {
408 HiiCreateActionOpCode (
409 StartOpCodeHandle,
410 FRONT_PAGE_KEY_CONTINUE,
411 STRING_TOKEN (STR_CONTINUE_PROMPT),
412 STRING_TOKEN (STR_CONTINUE_PROMPT),
413 EFI_IFR_FLAG_CALLBACK,
414 0
415 );
416 }
417
418 /**
419 Create empty line menu in the front page.
420
421 @param HiiHandle The hii handle for the Uiapp driver.
422 @param StartOpCodeHandle The opcode handle to save the new opcode.
423
424 **/
425 VOID
426 UiCreateEmptyLine (
427 IN EFI_HII_HANDLE HiiHandle,
428 IN VOID *StartOpCodeHandle
429 )
430 {
431 HiiCreateSubTitleOpCode (StartOpCodeHandle, STRING_TOKEN (STR_NULL_STRING), 0, 0, 0);
432 }
433
434 /**
435 Create Reset menu in the front page.
436
437 @param[in] HiiHandle The hii handle for the Uiapp driver.
438 @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
439
440 **/
441 VOID
442 UiCreateResetMenu (
443 IN EFI_HII_HANDLE HiiHandle,
444 IN VOID *StartOpCodeHandle
445 )
446 {
447 HiiCreateActionOpCode (
448 StartOpCodeHandle,
449 FRONT_PAGE_KEY_RESET,
450 STRING_TOKEN (STR_RESET_STRING),
451 STRING_TOKEN (STR_RESET_STRING),
452 EFI_IFR_FLAG_CALLBACK,
453 0
454 );
455 }
456
457 /**
458 Extract device path for given HII handle and class guid.
459
460 @param Handle The HII handle.
461
462 @retval NULL Fail to get the device path string.
463 @return PathString Get the device path string.
464
465 **/
466 CHAR16 *
467 ExtractDevicePathFromHiiHandle (
468 IN EFI_HII_HANDLE Handle
469 )
470 {
471 EFI_STATUS Status;
472 EFI_HANDLE DriverHandle;
473
474 ASSERT (Handle != NULL);
475
476 if (Handle == NULL) {
477 return NULL;
478 }
479
480 Status = gHiiDatabase->GetPackageListHandle (gHiiDatabase, Handle, &DriverHandle);
481 if (EFI_ERROR (Status)) {
482 return NULL;
483 }
484
485 return ConvertDevicePathToText(DevicePathFromHandle (DriverHandle), FALSE, FALSE);
486 }
487
488 /**
489 Check whether this driver need to be shown in the front page.
490
491 @param HiiHandle The hii handle for the driver.
492 @param Guid The special guid for the driver which is the target.
493 @param PromptId Return the prompt string id.
494 @param HelpId Return the help string id.
495 @param FormsetGuid Return the formset guid info.
496
497 @retval EFI_SUCCESS Search the driver success
498
499 **/
500 BOOLEAN
501 RequiredDriver (
502 IN EFI_HII_HANDLE HiiHandle,
503 IN EFI_GUID *Guid,
504 OUT EFI_STRING_ID *PromptId,
505 OUT EFI_STRING_ID *HelpId,
506 OUT VOID *FormsetGuid
507 )
508 {
509 EFI_STATUS Status;
510 UINT8 ClassGuidNum;
511 EFI_GUID *ClassGuid;
512 EFI_IFR_FORM_SET *Buffer;
513 UINTN BufferSize;
514 UINT8 *Ptr;
515 UINTN TempSize;
516 BOOLEAN RetVal;
517
518 Status = HiiGetFormSetFromHiiHandle(HiiHandle, &Buffer,&BufferSize);
519 if (EFI_ERROR (Status)) {
520 return FALSE;
521 }
522
523 RetVal = FALSE;
524 TempSize = 0;
525 Ptr = (UINT8 *) Buffer;
526 while(TempSize < BufferSize) {
527 TempSize += ((EFI_IFR_OP_HEADER *) Ptr)->Length;
528
529 if (((EFI_IFR_OP_HEADER *) Ptr)->Length <= OFFSET_OF (EFI_IFR_FORM_SET, Flags)){
530 Ptr += ((EFI_IFR_OP_HEADER *) Ptr)->Length;
531 continue;
532 }
533
534 ClassGuidNum = (UINT8) (((EFI_IFR_FORM_SET *)Ptr)->Flags & 0x3);
535 ClassGuid = (EFI_GUID *) (VOID *)(Ptr + sizeof (EFI_IFR_FORM_SET));
536 while (ClassGuidNum-- > 0) {
537 if (!CompareGuid (Guid, ClassGuid)){
538 ClassGuid ++;
539 continue;
540 }
541
542 *PromptId = ((EFI_IFR_FORM_SET *)Ptr)->FormSetTitle;
543 *HelpId = ((EFI_IFR_FORM_SET *)Ptr)->Help;
544 CopyMem (FormsetGuid, &((EFI_IFR_FORM_SET *) Ptr)->Guid, sizeof (EFI_GUID));
545 RetVal = TRUE;
546 }
547 }
548
549 FreePool (Buffer);
550
551 return RetVal;
552 }
553
554 /**
555 Search the drivers in the system which need to show in the front page
556 and insert the menu to the front page.
557
558 @param HiiHandle The hii handle for the Uiapp driver.
559 @param ClassGuid The class guid for the driver which is the target.
560 @param SpecialHandlerFn The pointer to the specail handler function, if any.
561 @param StartOpCodeHandle The opcode handle to save the new opcode.
562
563 @retval EFI_SUCCESS Search the driver success
564
565 **/
566 EFI_STATUS
567 UiListThirdPartyDrivers (
568 IN EFI_HII_HANDLE HiiHandle,
569 IN EFI_GUID *ClassGuid,
570 IN DRIVER_SPECIAL_HANDLER SpecialHandlerFn,
571 IN VOID *StartOpCodeHandle
572 )
573 {
574 UINTN Index;
575 EFI_STRING String;
576 EFI_STRING_ID Token;
577 EFI_STRING_ID TokenHelp;
578 EFI_HII_HANDLE *HiiHandles;
579 CHAR16 *DevicePathStr;
580 UINTN Count;
581 UINTN CurrentSize;
582 UI_HII_DRIVER_INSTANCE *DriverListPtr;
583 EFI_STRING NewName;
584 BOOLEAN EmptyLineAfter;
585
586 if (gHiiDriverList != NULL) {
587 FreePool (gHiiDriverList);
588 }
589
590 HiiHandles = HiiGetHiiHandles (NULL);
591 ASSERT (HiiHandles != NULL);
592
593 gHiiDriverList = AllocateZeroPool (UI_HII_DRIVER_LIST_SIZE * sizeof (UI_HII_DRIVER_INSTANCE));
594 ASSERT (gHiiDriverList != NULL);
595 DriverListPtr = gHiiDriverList;
596 CurrentSize = UI_HII_DRIVER_LIST_SIZE;
597
598 for (Index = 0, Count = 0; HiiHandles[Index] != NULL; Index++) {
599 if (!RequiredDriver (HiiHandles[Index], ClassGuid, &Token, &TokenHelp, &gHiiDriverList[Count].FormSetGuid)) {
600 continue;
601 }
602
603 String = HiiGetString (HiiHandles[Index], Token, NULL);
604 if (String == NULL) {
605 String = HiiGetString (gStringPackHandle, STRING_TOKEN (STR_MISSING_STRING), NULL);
606 ASSERT (String != NULL);
607 } else if (SpecialHandlerFn != NULL) {
608 //
609 // Check whether need to rename the driver name.
610 //
611 EmptyLineAfter = FALSE;
612 if (SpecialHandlerFn (String, &NewName, &EmptyLineAfter)) {
613 FreePool (String);
614 String = NewName;
615 DriverListPtr[Count].EmptyLineAfter = EmptyLineAfter;
616 }
617 }
618 DriverListPtr[Count].PromptId = HiiSetString (HiiHandle, 0, String, NULL);
619 FreePool (String);
620
621 String = HiiGetString (HiiHandles[Index], TokenHelp, NULL);
622 if (String == NULL) {
623 String = HiiGetString (gStringPackHandle, STRING_TOKEN (STR_MISSING_STRING), NULL);
624 ASSERT (String != NULL);
625 }
626 DriverListPtr[Count].HelpId = HiiSetString (HiiHandle, 0, String, NULL);
627 FreePool (String);
628
629 DevicePathStr = ExtractDevicePathFromHiiHandle(HiiHandles[Index]);
630 if (DevicePathStr != NULL){
631 DriverListPtr[Count].DevicePathId = HiiSetString (HiiHandle, 0, DevicePathStr, NULL);
632 FreePool (DevicePathStr);
633 } else {
634 DriverListPtr[Count].DevicePathId = 0;
635 }
636
637 Count++;
638 if (Count >= CurrentSize) {
639 DriverListPtr = AllocateCopyPool ((Count + UI_HII_DRIVER_LIST_SIZE) * sizeof (UI_HII_DRIVER_INSTANCE), gHiiDriverList);
640 ASSERT (DriverListPtr != NULL);
641 FreePool (gHiiDriverList);
642 gHiiDriverList = DriverListPtr;
643 CurrentSize += UI_HII_DRIVER_LIST_SIZE;
644 }
645 }
646
647 FreePool (HiiHandles);
648
649 Index = 0;
650 while (gHiiDriverList[Index].PromptId != 0) {
651 HiiCreateGotoExOpCode (
652 StartOpCodeHandle,
653 0,
654 gHiiDriverList[Index].PromptId,
655 gHiiDriverList[Index].HelpId,
656 0,
657 0,
658 0,
659 &gHiiDriverList[Index].FormSetGuid,
660 gHiiDriverList[Index].DevicePathId
661 );
662
663 if (gHiiDriverList[Index].EmptyLineAfter) {
664 UiCreateEmptyLine (HiiHandle, StartOpCodeHandle);
665 }
666
667 Index ++;
668 }
669
670 return EFI_SUCCESS;
671 }