Add the missing HiiVendor DevicePath for new added DriverHealth Form.
[efi/edk2/.git] / edk2 / IntelFrameworkModulePkg / Universal / BdsDxe / DeviceMngr / DeviceManager.c
1 /** @file\r
2   The platform device manager reference implementation\r
3 \r
4 Copyright (c) 2004 - 2009, Intel Corporation. <BR>\r
5 All rights reserved. This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution.  The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9 \r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12 \r
13 **/\r
14 \r
15 #include "DeviceManager.h"\r
16 \r
17 DEVICE_MANAGER_CALLBACK_DATA  gDeviceManagerPrivate = {\r
18   DEVICE_MANAGER_CALLBACK_DATA_SIGNATURE,\r
19   NULL,\r
20   NULL,\r
21   NULL,\r
22   NULL,\r
23   {\r
24     FakeExtractConfig,\r
25     FakeRouteConfig,\r
26     DeviceManagerCallback\r
27   },\r
28   {\r
29     FakeExtractConfig,\r
30     FakeRouteConfig,\r
31     DriverHealthCallback\r
32   }\r
33 };\r
34 \r
35 EFI_GUID mDeviceManagerGuid = DEVICE_MANAGER_FORMSET_GUID;\r
36 EFI_GUID mDriverHealthGuid = DRIVER_HEALTH_FORMSET_GUID;\r
37 \r
38 DEVICE_MANAGER_MENU_ITEM  mDeviceManagerMenuItemTable[] = {\r
39   { STRING_TOKEN (STR_DISK_DEVICE),     EFI_DISK_DEVICE_CLASS },\r
40   { STRING_TOKEN (STR_VIDEO_DEVICE),    EFI_VIDEO_DEVICE_CLASS },\r
41   { STRING_TOKEN (STR_NETWORK_DEVICE),  EFI_NETWORK_DEVICE_CLASS },\r
42   { STRING_TOKEN (STR_INPUT_DEVICE),    EFI_INPUT_DEVICE_CLASS },\r
43   { STRING_TOKEN (STR_ON_BOARD_DEVICE), EFI_ON_BOARD_DEVICE_CLASS },\r
44   { STRING_TOKEN (STR_OTHER_DEVICE),    EFI_OTHER_DEVICE_CLASS }\r
45 };\r
46 \r
47 HII_VENDOR_DEVICE_PATH  mDeviceManagerHiiVendorDevicePath = {\r
48   {\r
49     {\r
50       HARDWARE_DEVICE_PATH,\r
51       HW_VENDOR_DP,\r
52       {\r
53         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),\r
54         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)\r
55       }\r
56     },\r
57     //\r
58     // {102579A0-3686-466e-ACD8-80C087044F4A}\r
59     //\r
60     { 0x102579a0, 0x3686, 0x466e, { 0xac, 0xd8, 0x80, 0xc0, 0x87, 0x4, 0x4f, 0x4a } }\r
61   },\r
62   {\r
63     END_DEVICE_PATH_TYPE,\r
64     END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
65     { \r
66       (UINT8) (END_DEVICE_PATH_LENGTH),\r
67       (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)\r
68     }\r
69   }\r
70 };\r
71 \r
72 HII_VENDOR_DEVICE_PATH  mDriverHealthHiiVendorDevicePath = {\r
73   {\r
74     {\r
75       HARDWARE_DEVICE_PATH,\r
76         HW_VENDOR_DP,\r
77       {\r
78         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),\r
79           (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)\r
80       }\r
81     },\r
82     //\r
83     // {D8F76651-1675-4986-BED4-3824B2F1F4C8}\r
84     //\r
85     { 0xd8f76651, 0x1675, 0x4986, { 0xbe, 0xd4, 0x38, 0x24, 0xb2, 0xf1, 0xf4, 0xc8 } }\r
86   },\r
87   {\r
88     END_DEVICE_PATH_TYPE,\r
89       END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
90     { \r
91       (UINT8) (END_DEVICE_PATH_LENGTH),\r
92         (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)\r
93     }\r
94   }\r
95 };\r
96 \r
97 /**\r
98   This function is invoked if user selected a interactive opcode from Device Manager's\r
99   Formset. The decision by user is saved to gCallbackKey for later processing. If\r
100   user set VBIOS, the new value is saved to EFI variable.\r
101 \r
102   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
103   @param Action          Specifies the type of action taken by the browser.\r
104   @param QuestionId      A unique value which is sent to the original exporting driver\r
105                          so that it can identify the type of data to expect.\r
106   @param Type            The type of value for the question.\r
107   @param Value           A pointer to the data being sent to the original exporting driver.\r
108   @param ActionRequest   On return, points to the action requested by the callback function.\r
109 \r
110   @retval  EFI_SUCCESS           The callback successfully handled the action.\r
111   @retval  EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.\r
112 \r
113 **/\r
114 EFI_STATUS\r
115 EFIAPI\r
116 DeviceManagerCallback (\r
117   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,\r
118   IN  EFI_BROWSER_ACTION                     Action,\r
119   IN  EFI_QUESTION_ID                        QuestionId,\r
120   IN  UINT8                                  Type,\r
121   IN  EFI_IFR_TYPE_VALUE                     *Value,\r
122   OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest\r
123   )\r
124 {\r
125   if ((Value == NULL) || (ActionRequest == NULL)) {\r
126     return EFI_INVALID_PARAMETER;\r
127   }\r
128 \r
129   gCallbackKey = QuestionId;\r
130 \r
131   //\r
132   // Request to exit SendForm(), so as to switch to selected form\r
133   //\r
134   *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;\r
135 \r
136   return EFI_SUCCESS;\r
137 }\r
138 \r
139 /**\r
140 \r
141   This function registers HII packages to HII database.\r
142 \r
143   @retval  EFI_SUCCESS           HII packages for the Device Manager were registered successfully.\r
144   @retval  EFI_OUT_OF_RESOURCES  HII packages for the Device Manager failed to be registered.\r
145 \r
146 **/\r
147 EFI_STATUS\r
148 InitializeDeviceManager (\r
149   VOID\r
150   )\r
151 {\r
152   EFI_STATUS                  Status;\r
153 \r
154   //\r
155   // Install Device Path Protocol and Config Access protocol to driver handle\r
156   //\r
157   Status = gBS->InstallMultipleProtocolInterfaces (\r
158                   &gDeviceManagerPrivate.DriverHandle,\r
159                   &gEfiDevicePathProtocolGuid,\r
160                   &mDeviceManagerHiiVendorDevicePath,\r
161                   &gEfiHiiConfigAccessProtocolGuid,\r
162                   &gDeviceManagerPrivate.ConfigAccess,\r
163                   NULL\r
164                   );\r
165   ASSERT_EFI_ERROR (Status);\r
166 \r
167   Status = gBS->InstallMultipleProtocolInterfaces (\r
168                   &gDeviceManagerPrivate.DriverHealthHandle,\r
169                   &gEfiDevicePathProtocolGuid,\r
170                   &mDriverHealthHiiVendorDevicePath,\r
171                   &gEfiHiiConfigAccessProtocolGuid,\r
172                   &gDeviceManagerPrivate.DriverHealthConfigAccess,\r
173                   NULL\r
174                   );\r
175   ASSERT_EFI_ERROR (Status);\r
176 \r
177   //\r
178   // Publish our HII data\r
179   //\r
180   gDeviceManagerPrivate.HiiHandle = HiiAddPackages (\r
181                                       &mDeviceManagerGuid,\r
182                                       gDeviceManagerPrivate.DriverHandle,\r
183                                       DeviceManagerVfrBin,\r
184                                       BdsDxeStrings,\r
185                                       NULL\r
186                                       );\r
187   if (gDeviceManagerPrivate.HiiHandle == NULL) {\r
188     return EFI_OUT_OF_RESOURCES;\r
189   } else {\r
190     Status = EFI_SUCCESS;\r
191   }\r
192   \r
193   //\r
194   // Publish Driver Health HII data\r
195   //\r
196   gDeviceManagerPrivate.DriverHealthHiiHandle = HiiAddPackages (\r
197                                                   &mDeviceManagerGuid,\r
198                                                   gDeviceManagerPrivate.DriverHealthHandle,\r
199                                                   DriverHealthVfrBin,\r
200                                                   BdsDxeStrings,\r
201                                                   NULL\r
202                                                   );\r
203   if (gDeviceManagerPrivate.DriverHealthHiiHandle == NULL) {\r
204     Status = EFI_OUT_OF_RESOURCES;\r
205   } else {\r
206     Status = EFI_SUCCESS;\r
207   }\r
208 \r
209   return Status;\r
210 }\r
211 \r
212 /**\r
213   Extract the displayed formset for given HII handle and class guid.\r
214 \r
215   @param Handle          The HII handle.\r
216   @param SetupClassGuid  The class guid specifies which form set will be displayed.\r
217   @param FormSetTitle    Formset title string.\r
218   @param FormSetHelp     Formset help string.\r
219 \r
220   @retval  TRUE          The formset for given HII handle will be displayed.\r
221   @return  FALSE         The formset for given HII handle will not be displayed.\r
222 \r
223 **/\r
224 BOOLEAN\r
225 ExtractDisplayedHiiFormFromHiiHandle (\r
226   IN      EFI_HII_HANDLE      Handle,\r
227   IN      EFI_GUID            *SetupClassGuid,\r
228   OUT     EFI_STRING_ID       *FormSetTitle,\r
229   OUT     EFI_STRING_ID       *FormSetHelp\r
230   )\r
231 {\r
232   EFI_STATUS                   Status;\r
233   UINTN                        BufferSize;\r
234   EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;\r
235   UINT8                        *Package;\r
236   UINT8                        *OpCodeData;\r
237   UINT32                       Offset;\r
238   UINT32                       Offset2;\r
239   UINT32                       PackageListLength;\r
240   EFI_HII_PACKAGE_HEADER       PackageHeader;\r
241   EFI_GUID                     *ClassGuid;\r
242   UINT8                        ClassGuidNum;\r
243 \r
244   ASSERT (Handle != NULL);\r
245   ASSERT (SetupClassGuid != NULL);  \r
246   ASSERT (FormSetTitle != NULL);\r
247   ASSERT (FormSetHelp != NULL);\r
248 \r
249   *FormSetTitle = 0;\r
250   *FormSetHelp  = 0;\r
251   ClassGuidNum  = 0;\r
252   ClassGuid     = NULL;\r
253 \r
254   //\r
255   // Get HII PackageList\r
256   //\r
257   BufferSize = 0;\r
258   HiiPackageList = NULL;\r
259   Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &BufferSize, HiiPackageList);\r
260   //\r
261   // Handle is a invalid handle. Check if Handle is corrupted.\r
262   //\r
263   ASSERT (Status != EFI_NOT_FOUND);\r
264   //\r
265   // The return status should always be EFI_BUFFER_TOO_SMALL as input buffer's size is 0.\r
266   //\r
267   ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
268   \r
269   HiiPackageList = AllocatePool (BufferSize);\r
270   ASSERT (HiiPackageList != NULL);\r
271 \r
272   Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &BufferSize, HiiPackageList);\r
273   if (EFI_ERROR (Status)) {\r
274     return FALSE;\r
275   }\r
276 \r
277   //\r
278   // Get Form package from this HII package List\r
279   //\r
280   Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);\r
281   Offset2 = 0;\r
282   PackageListLength = ReadUnaligned32 (&HiiPackageList->PackageLength);\r
283 \r
284   while (Offset < PackageListLength) {\r
285     Package = ((UINT8 *) HiiPackageList) + Offset;\r
286     CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));\r
287 \r
288     if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {\r
289       //\r
290       // Search FormSet Opcode in this Form Package\r
291       //\r
292       Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);\r
293       while (Offset2 < PackageHeader.Length) {\r
294         OpCodeData = Package + Offset2;\r
295 \r
296         if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {\r
297           //\r
298           // Find FormSet OpCode\r
299           //\r
300           ClassGuidNum = ((EFI_IFR_FORM_SET *) OpCodeData)->Flags;\r
301           ClassGuid = (EFI_GUID *) (VOID *)(OpCodeData + sizeof (EFI_IFR_FORM_SET));\r
302           while (ClassGuidNum-- > 0) {\r
303             if (CompareGuid (SetupClassGuid, ClassGuid)) {\r
304               CopyMem (FormSetTitle, &((EFI_IFR_FORM_SET *) OpCodeData)->FormSetTitle, sizeof (EFI_STRING_ID));\r
305               CopyMem (FormSetHelp, &((EFI_IFR_FORM_SET *) OpCodeData)->Help, sizeof (EFI_STRING_ID));\r
306               FreePool (HiiPackageList);\r
307               return TRUE;\r
308             }\r
309           }\r
310         }\r
311         \r
312         //\r
313         // Go to next opcode\r
314         //\r
315         Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;\r
316       }\r
317     }\r
318     \r
319     //\r
320     // Go to next package\r
321     //\r
322     Offset += PackageHeader.Length;\r
323   }\r
324 \r
325   FreePool (HiiPackageList);\r
326 \r
327   return FALSE;\r
328 }\r
329 \r
330 /**\r
331   Call the browser and display the device manager to allow user\r
332   to configure the platform.\r
333 \r
334   This function create the dynamic content for device manager. It includes\r
335   section header for all class of devices, one-of opcode to set VBIOS.\r
336   \r
337   @retval  EFI_SUCCESS             Operation is successful.\r
338   @return  Other values if failed to clean up the dynamic content from HII\r
339            database.\r
340 \r
341 **/\r
342 EFI_STATUS\r
343 CallDeviceManager (\r
344   VOID\r
345   )\r
346 {\r
347   EFI_STATUS                  Status;\r
348   UINTN                       Index;\r
349   EFI_STRING                  String;\r
350   EFI_STRING_ID               Token;\r
351   EFI_STRING_ID               TokenHelp;\r
352   EFI_HII_HANDLE              *HiiHandles;\r
353   EFI_HII_HANDLE              HiiHandle;\r
354   EFI_STRING_ID               FormSetTitle;\r
355   EFI_STRING_ID               FormSetHelp;\r
356   EFI_BROWSER_ACTION_REQUEST  ActionRequest;\r
357   VOID                        *StartOpCodeHandle;\r
358   VOID                        *EndOpCodeHandle;\r
359   EFI_IFR_GUID_LABEL          *StartLabel;\r
360   EFI_IFR_GUID_LABEL          *EndLabel;\r
361   UINTN                       NumHandles;\r
362   EFI_HANDLE                  *DriverHealthHandles;\r
363 \r
364   HiiHandles    = NULL;\r
365   Status        = EFI_SUCCESS;\r
366   gCallbackKey  = 0;\r
367   NumHandles    = 0;\r
368   DriverHealthHandles = NULL;\r
369 \r
370   //\r
371   // Connect all prior to entering the platform setup menu.\r
372   //\r
373   if (!gConnectAllHappened) {\r
374     BdsLibConnectAllDriversToAllControllers ();\r
375     gConnectAllHappened = TRUE;\r
376   }\r
377   //\r
378   // Create Subtitle OpCodes\r
379   //\r
380   //\r
381   // Allocate space for creation of UpdateData Buffer\r
382   //\r
383   StartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
384   ASSERT (StartOpCodeHandle != NULL);\r
385 \r
386   EndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
387   ASSERT (EndOpCodeHandle != NULL);\r
388 \r
389   //\r
390   // Create Hii Extend Label OpCode as the start opcode\r
391   //\r
392   StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));\r
393   StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
394   StartLabel->Number       = LABEL_DEVICES_LIST;\r
395 \r
396   //\r
397   // Create Hii Extend Label OpCode as the end opcode\r
398   //\r
399   EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));\r
400   EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
401   EndLabel->Number       = LABEL_END;\r
402 \r
403   HiiCreateSubTitleOpCode (StartOpCodeHandle, STRING_TOKEN (STR_DEVICES_LIST), 0, 0, 1);\r
404 \r
405   //\r
406   // Get all the Hii handles\r
407   //\r
408   HiiHandles = HiiGetHiiHandles (NULL);\r
409   ASSERT (HiiHandles != NULL);\r
410 \r
411   HiiHandle = gDeviceManagerPrivate.HiiHandle;\r
412 \r
413   //\r
414   // Search for formset of each class type\r
415   //\r
416   for (Index = 0; HiiHandles[Index] != NULL; Index++) {\r
417     if (!ExtractDisplayedHiiFormFromHiiHandle (HiiHandles[Index], &gEfiHiiPlatformSetupFormsetGuid, &FormSetTitle, &FormSetHelp)) {\r
418       continue;\r
419     }\r
420 \r
421     String = HiiGetString (HiiHandles[Index], FormSetTitle, NULL);\r
422     if (String == NULL) {\r
423       String = HiiGetString (HiiHandle, STR_MISSING_STRING, NULL);\r
424       ASSERT (String != NULL);\r
425     }\r
426     Token = HiiSetString (HiiHandle, 0, String, NULL);\r
427     FreePool (String);\r
428 \r
429     String = HiiGetString (HiiHandles[Index], FormSetHelp, NULL);\r
430     if (String == NULL) {\r
431       String = HiiGetString (HiiHandle, STR_MISSING_STRING, NULL);\r
432       ASSERT (String != NULL);\r
433     }\r
434     TokenHelp = HiiSetString (HiiHandle, 0, String, NULL);\r
435     FreePool (String);\r
436 \r
437     HiiCreateActionOpCode (\r
438       StartOpCodeHandle,\r
439       (EFI_QUESTION_ID) (Index + DEVICE_KEY_OFFSET),\r
440       Token,\r
441       TokenHelp,\r
442       EFI_IFR_FLAG_CALLBACK,\r
443       0\r
444       );\r
445   }\r
446 \r
447   //\r
448   // Add End Opcode for Subtitle\r
449   //\r
450   HiiCreateEndOpCode (StartOpCodeHandle);\r
451 \r
452   Status = gBS->LocateHandleBuffer (\r
453                 ByProtocol,\r
454                 &gEfiDriverHealthProtocolGuid,\r
455                 NULL,\r
456                 &NumHandles,\r
457                 &DriverHealthHandles\r
458                 );\r
459   //\r
460   // If there are no drivers installed driver health protocol\r
461   //\r
462   if (NumHandles == 0) {\r
463     HiiSetString (HiiHandle, STRING_TOKEN (STR_DM_DRIVER_HEALTH_TITLE), GetStringById (STRING_TOKEN (STR_EMPTY_STRING)), NULL);\r
464     HiiSetString (HiiHandle, STRING_TOKEN (STR_DRIVER_HEALTH_ALL_HEALTHY), GetStringById (STRING_TOKEN (STR_EMPTY_STRING)), NULL);\r
465   } else {\r
466     //\r
467     // Check All Driver health status\r
468     //\r
469     if (!PlaformHealthStatusCheck ()) {\r
470       //\r
471       // At least one driver in the platform are not in healthy status\r
472       //\r
473       HiiSetString (HiiHandle, STRING_TOKEN (STR_DRIVER_HEALTH_ALL_HEALTHY), GetStringById (STRING_TOKEN (STR_DRIVER_NOT_HEALTH)), NULL);\r
474     } else {\r
475       //\r
476       // For the string of STR_DRIVER_HEALTH_ALL_HEALTHY previously has been updated and we need to update it while re-entry.\r
477       //\r
478       HiiSetString (HiiHandle, STRING_TOKEN (STR_DRIVER_HEALTH_ALL_HEALTHY), GetStringById (STRING_TOKEN (STR_DRIVER_HEALTH_ALL_HEALTHY)), NULL);\r
479     }\r
480   }\r
481 \r
482   HiiUpdateForm (\r
483     HiiHandle,\r
484     &mDeviceManagerGuid,\r
485     DEVICE_MANAGER_FORM_ID,\r
486     StartOpCodeHandle,\r
487     EndOpCodeHandle\r
488     );\r
489 \r
490   ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
491   Status = gFormBrowser2->SendForm (\r
492                            gFormBrowser2,\r
493                            &HiiHandle,\r
494                            1,\r
495                            &mDeviceManagerGuid,\r
496                            0,\r
497                            NULL,\r
498                            &ActionRequest\r
499                            );\r
500   if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {\r
501     EnableResetRequired ();\r
502   }\r
503 \r
504   //\r
505   // We will have returned from processing a callback - user either hit ESC to exit, or selected\r
506   // a target to display\r
507   //\r
508   if ((gCallbackKey != 0) && (gCallbackKey != DEVICE_MANAGER_KEY_DRIVER_HEALTH)) {\r
509     ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
510     Status = gFormBrowser2->SendForm (\r
511                              gFormBrowser2,\r
512                              &HiiHandles[gCallbackKey - DEVICE_KEY_OFFSET],\r
513                              1,\r
514                              NULL,\r
515                              0,\r
516                              NULL,\r
517                              &ActionRequest\r
518                              );\r
519 \r
520     if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {\r
521       EnableResetRequired ();\r
522     }\r
523 \r
524     //\r
525     // Force return to Device Manager\r
526     //\r
527     gCallbackKey = FRONT_PAGE_KEY_DEVICE_MANAGER;\r
528   }\r
529 \r
530   //\r
531   // Driver Health item chose. \r
532   //\r
533   if (gCallbackKey == DEVICE_MANAGER_KEY_DRIVER_HEALTH) {\r
534     CallDriverHealth ();\r
535     //\r
536     // Force return to Device Manager\r
537     //\r
538     gCallbackKey = FRONT_PAGE_KEY_DEVICE_MANAGER;\r
539   }\r
540 \r
541   //\r
542   // Cleanup dynamic created strings in HII database by reinstall the packagelist\r
543   //\r
544   HiiRemovePackages (HiiHandle);\r
545 \r
546   gDeviceManagerPrivate.HiiHandle = HiiAddPackages (\r
547                                       &mDeviceManagerGuid,\r
548                                       gDeviceManagerPrivate.DriverHandle,\r
549                                       DeviceManagerVfrBin,\r
550                                       BdsDxeStrings,\r
551                                       NULL\r
552                                       );\r
553   if (gDeviceManagerPrivate.HiiHandle == NULL) {\r
554     Status = EFI_OUT_OF_RESOURCES;\r
555   } else {\r
556     Status = EFI_SUCCESS;\r
557   }\r
558 \r
559   HiiFreeOpCodeHandle (StartOpCodeHandle);\r
560   HiiFreeOpCodeHandle (EndOpCodeHandle);\r
561   FreePool (HiiHandles);\r
562 \r
563   return Status;\r
564 }\r
565 \r
566 /**\r
567   This function is invoked if user selected a interactive opcode from Driver Health's\r
568   Formset. The decision by user is saved to gCallbackKey for later processing.\r
569 \r
570   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
571   @param Action          Specifies the type of action taken by the browser.\r
572   @param QuestionId      A unique value which is sent to the original exporting driver\r
573                          so that it can identify the type of data to expect.\r
574   @param Type            The type of value for the question.\r
575   @param Value           A pointer to the data being sent to the original exporting driver.\r
576   @param ActionRequest   On return, points to the action requested by the callback function.\r
577 \r
578   @retval  EFI_SUCCESS           The callback successfully handled the action.\r
579   @retval  EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.\r
580 \r
581 **/\r
582 EFI_STATUS\r
583 EFIAPI\r
584 DriverHealthCallback (\r
585   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,\r
586   IN  EFI_BROWSER_ACTION                     Action,\r
587   IN  EFI_QUESTION_ID                        QuestionId,\r
588   IN  UINT8                                  Type,\r
589   IN  EFI_IFR_TYPE_VALUE                     *Value,\r
590   OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest\r
591   )\r
592 {\r
593   if ((Value == NULL) || (ActionRequest == NULL)) {\r
594     return EFI_INVALID_PARAMETER;\r
595   }\r
596 \r
597   gCallbackKey = QuestionId;\r
598 \r
599   //\r
600   // Request to exit SendForm(), so as to switch to selected form\r
601   //\r
602   *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;\r
603 \r
604   return EFI_SUCCESS;\r
605 }\r
606 \r
607 /**\r
608   Collect and display the platform's driver health relative information, allow user to do interactive \r
609   operation while the platform is unhealthy.\r
610 \r
611   This function display a form which divided into two parts. The one list all modules which has installed \r
612   driver health protocol. The list usually contain driver name, controller name, and it's health info.\r
613   While the driver name can't be retrieved, will use device path as backup. The other part of the form provide\r
614   a choice to the user to repair all platform.\r
615 \r
616 **/\r
617 VOID\r
618 CallDriverHealth (\r
619   VOID\r
620   )\r
621 {\r
622   EFI_STATUS                  Status; \r
623   EFI_HII_HANDLE              HiiHandle;\r
624   EFI_BROWSER_ACTION_REQUEST  ActionRequest;\r
625   EFI_IFR_GUID_LABEL          *StartLabel;\r
626   EFI_IFR_GUID_LABEL          *StartLabelRepair;\r
627   EFI_IFR_GUID_LABEL          *EndLabel;\r
628   EFI_IFR_GUID_LABEL          *EndLabelRepair;\r
629   VOID                        *StartOpCodeHandle;\r
630   VOID                        *EndOpCodeHandle;\r
631   VOID                        *StartOpCodeHandleRepair;\r
632   VOID                        *EndOpCodeHandleRepair;\r
633   UINTN                       Index;\r
634   EFI_STRING_ID               Token;\r
635   EFI_STRING_ID               TokenHelp;\r
636   EFI_STRING                  String;\r
637   EFI_STRING                  TmpString;\r
638   EFI_STRING                  DriverName;\r
639   EFI_STRING                  ControllerName;\r
640   LIST_ENTRY                  DriverHealthList;\r
641   DRIVER_HEALTH_INFO          *DriverHealthInfo;\r
642   LIST_ENTRY                  *Link;\r
643   EFI_DEVICE_PATH_PROTOCOL    *DriverDevicePath;\r
644   UINTN                       Length;\r
645 \r
646   HiiHandle           = gDeviceManagerPrivate.DriverHealthHiiHandle;\r
647   Index               = 0;\r
648   Length              = 0;\r
649   DriverHealthInfo    = NULL;  \r
650   DriverDevicePath    = NULL;\r
651   InitializeListHead (&DriverHealthList);\r
652 \r
653   //\r
654   // Allocate space for creation of UpdateData Buffer\r
655   //\r
656   StartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
657   ASSERT (StartOpCodeHandle != NULL);\r
658 \r
659   EndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
660   ASSERT (EndOpCodeHandle != NULL);\r
661 \r
662   StartOpCodeHandleRepair = HiiAllocateOpCodeHandle ();\r
663   ASSERT (StartOpCodeHandleRepair != NULL);\r
664 \r
665   EndOpCodeHandleRepair = HiiAllocateOpCodeHandle ();\r
666   ASSERT (EndOpCodeHandleRepair != NULL);\r
667 \r
668   //\r
669   // Create Hii Extend Label OpCode as the start opcode\r
670   //\r
671   StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));\r
672   StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
673   StartLabel->Number       = LABEL_DRIVER_HEALTH;\r
674 \r
675   //\r
676   // Create Hii Extend Label OpCode as the start opcode\r
677   //\r
678   StartLabelRepair = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandleRepair, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));\r
679   StartLabelRepair->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
680   StartLabelRepair->Number       = LABEL_DRIVER_HEALTH_REAPIR_ALL;\r
681 \r
682   //\r
683   // Create Hii Extend Label OpCode as the end opcode\r
684   //\r
685   EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));\r
686   EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
687   EndLabel->Number       = LABEL_DRIVER_HEALTH_END;\r
688 \r
689   //\r
690   // Create Hii Extend Label OpCode as the end opcode\r
691   //\r
692   EndLabelRepair = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandleRepair, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));\r
693   EndLabelRepair->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
694   EndLabelRepair->Number       = LABEL_DRIVER_HEALTH_REAPIR_ALL_END;\r
695 \r
696   HiiCreateSubTitleOpCode (StartOpCodeHandle, STRING_TOKEN (STR_DH_STATUS_LIST), 0, 0, 1);\r
697 \r
698   Status = GetAllControllersHealthStatus (&DriverHealthList);\r
699   ASSERT (Status != EFI_OUT_OF_RESOURCES);\r
700 \r
701   Link = GetFirstNode (&DriverHealthList);\r
702 \r
703   while (!IsNull (&DriverHealthList, Link)) {   \r
704     DriverHealthInfo = DEVICE_MANAGER_HEALTH_INFO_FROM_LINK (Link);\r
705     \r
706     //\r
707     // Assume no line strings is longer than 512 bytes.\r
708     //\r
709     String = (EFI_STRING) AllocateZeroPool (0x200);\r
710     ASSERT (String != NULL);\r
711 \r
712     Status = DriverHealthGetDriverName (DriverHealthInfo->DriverHandle, &DriverName);\r
713     if (EFI_ERROR (Status)) {\r
714       //\r
715       // Can not get the Driver name, so use the Device path\r
716       //\r
717       DriverDevicePath = DevicePathFromHandle (DriverHealthInfo->DriverHandle);\r
718       DriverName       = DevicePathToStr (DriverDevicePath);\r
719     }\r
720     //\r
721     // Add the Driver name & Controller name into FormSetTitle string\r
722     // \r
723     StrnCat (String, DriverName, StrLen (DriverName));\r
724 \r
725 \r
726     Status = DriverHealthGetControllerName (\r
727                DriverHealthInfo->DriverHandle, \r
728                DriverHealthInfo->ControllerHandle, \r
729                DriverHealthInfo->ChildHandle, \r
730                &ControllerName\r
731                );\r
732 \r
733     if (!EFI_ERROR (Status)) {\r
734       //\r
735       // Can not get the Controller name, just let it empty.\r
736       //\r
737       StrnCat (String, L"    ", StrLen (L"    "));\r
738       StrnCat (String, ControllerName, StrLen (ControllerName));   \r
739     }\r
740    \r
741     //\r
742     // Add the message of the Module itself provided after the string item.\r
743     //\r
744     if ((DriverHealthInfo->MessageList != NULL) && (DriverHealthInfo->MessageList->StringId != 0)) {\r
745        StrnCat (String, L"    ", StrLen (L"    "));\r
746        TmpString = HiiGetString (\r
747                      DriverHealthInfo->MessageList->HiiHandle, \r
748                      DriverHealthInfo->MessageList->StringId, \r
749                      NULL\r
750                      );\r
751        //\r
752        // Assert if can not retrieve the message string\r
753        //\r
754        ASSERT (TmpString != NULL);\r
755        StrnCat (String, TmpString, StrLen (TmpString));\r
756        FreePool (TmpString);\r
757     } else {\r
758       //\r
759       // Update the string will be displayed base on the driver's health status\r
760       //\r
761       switch(DriverHealthInfo->HealthStatus) {\r
762       case EfiDriverHealthStatusRepairRequired:\r
763         Length = StrLen (GetStringById (STRING_TOKEN (STR_REPAIR_REQUIRED)));\r
764         StrnCat (String, GetStringById (STRING_TOKEN (STR_REPAIR_REQUIRED)), Length);\r
765         break;\r
766       case EfiDriverHealthStatusConfigurationRequired:\r
767         Length = StrLen (GetStringById (STRING_TOKEN (STR_CONFIGURATION_REQUIRED)));\r
768         StrnCat (String, GetStringById (STRING_TOKEN (STR_CONFIGURATION_REQUIRED)), Length);\r
769         break;\r
770       case EfiDriverHealthStatusFailed:\r
771         Length = StrLen (GetStringById (STRING_TOKEN (STR_OPERATION_FAILED)));\r
772         StrnCat (String, GetStringById (STRING_TOKEN (STR_OPERATION_FAILED)), Length);\r
773         break;\r
774       case EfiDriverHealthStatusReconnectRequired:\r
775         Length = StrLen (GetStringById (STRING_TOKEN (STR_RECONNECT_REQUIRED)));\r
776         StrnCat (String, GetStringById (STRING_TOKEN (STR_RECONNECT_REQUIRED)), Length);\r
777         break;\r
778       case EfiDriverHealthStatusRebootRequired:\r
779         Length = StrLen (GetStringById (STRING_TOKEN (STR_REBOOT_REQUIRED)));\r
780         StrnCat (String, GetStringById (STRING_TOKEN (STR_REBOOT_REQUIRED)), Length);\r
781         break;\r
782       default:\r
783         Length = StrLen (GetStringById (STRING_TOKEN (STR_DRIVER_HEALTH_HEALTHY)));\r
784         StrnCat (String, GetStringById (STRING_TOKEN (STR_DRIVER_HEALTH_HEALTHY)), Length);\r
785         break;\r
786       }\r
787     }\r
788 \r
789     Token = HiiSetString (HiiHandle, 0, String, NULL);\r
790     FreePool (String);\r
791 \r
792     TokenHelp = HiiSetString (HiiHandle, 0, GetStringById( STRING_TOKEN (STR_DH_REPAIR_SINGLE_HELP)), NULL);\r
793 \r
794     HiiCreateActionOpCode (\r
795       StartOpCodeHandle,\r
796       (EFI_QUESTION_ID) (Index + DRIVER_HEALTH_KEY_OFFSET),\r
797       Token,\r
798       TokenHelp,\r
799       EFI_IFR_FLAG_CALLBACK,\r
800       0\r
801       );\r
802     Index++;\r
803     Link = GetNextNode (&DriverHealthList, Link);\r
804   }\r
805    \r
806   //\r
807   // Add End Opcode for Subtitle\r
808   // \r
809   HiiCreateEndOpCode (StartOpCodeHandle);\r
810 \r
811   HiiCreateSubTitleOpCode (StartOpCodeHandleRepair, STRING_TOKEN (STR_DRIVER_HEALTH_REPAIR_ALL), 0, 0, 1);\r
812   TokenHelp = HiiSetString (HiiHandle, 0, GetStringById( STRING_TOKEN (STR_DH_REPAIR_ALL_HELP)), NULL);  \r
813 \r
814   if (PlaformHealthStatusCheck ()) {\r
815     //\r
816     // No action need to do for the platform\r
817     //\r
818     Token = HiiSetString (HiiHandle, 0, GetStringById( STRING_TOKEN (STR_DRIVER_HEALTH_ALL_HEALTHY)), NULL);\r
819     HiiCreateActionOpCode (\r
820       StartOpCodeHandleRepair,\r
821       0,\r
822       Token,\r
823       TokenHelp,\r
824       EFI_IFR_FLAG_READ_ONLY,\r
825       0\r
826       );\r
827   } else {\r
828     //\r
829     // Create ActionOpCode only while the platform need to do health related operation.\r
830     //\r
831     Token = HiiSetString (HiiHandle, 0, GetStringById( STRING_TOKEN (STR_DH_REPAIR_ALL_TITLE)), NULL);\r
832     HiiCreateActionOpCode (\r
833       StartOpCodeHandleRepair,\r
834       (EFI_QUESTION_ID) DRIVER_HEALTH_REPAIR_ALL_KEY,\r
835       Token,\r
836       TokenHelp,\r
837       EFI_IFR_FLAG_CALLBACK,\r
838       0\r
839       );\r
840   }\r
841 \r
842   HiiCreateEndOpCode (StartOpCodeHandleRepair);\r
843 \r
844   Status = HiiUpdateForm (\r
845              HiiHandle,\r
846              &mDriverHealthGuid,\r
847              DRIVER_HEALTH_FORM_ID,\r
848              StartOpCodeHandle,\r
849              EndOpCodeHandle\r
850              );\r
851   ASSERT (Status != EFI_NOT_FOUND);\r
852   ASSERT (Status != EFI_BUFFER_TOO_SMALL);\r
853 \r
854   Status = HiiUpdateForm (\r
855             HiiHandle,\r
856             &mDriverHealthGuid,\r
857             DRIVER_HEALTH_FORM_ID,\r
858             StartOpCodeHandleRepair,\r
859             EndOpCodeHandleRepair\r
860     );\r
861   ASSERT (Status != EFI_NOT_FOUND);\r
862   ASSERT (Status != EFI_BUFFER_TOO_SMALL);\r
863 \r
864   ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
865   Status = gFormBrowser2->SendForm (\r
866                            gFormBrowser2,\r
867                            &HiiHandle,\r
868                            1,\r
869                            &mDriverHealthGuid,\r
870                            DRIVER_HEALTH_FORM_ID,\r
871                            NULL,\r
872                            &ActionRequest\r
873                            );\r
874   if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {\r
875     EnableResetRequired ();\r
876   }\r
877 \r
878   //\r
879   // We will have returned from processing a callback - user either hit ESC to exit, or selected\r
880   // a target to display.\r
881   // Process the diver health status states here.\r
882   // \r
883   if (gCallbackKey >= DRIVER_HEALTH_KEY_OFFSET && gCallbackKey != DRIVER_HEALTH_REPAIR_ALL_KEY) {\r
884     ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
885 \r
886     Link = GetFirstNode (&DriverHealthList);\r
887     Index = 0;\r
888 \r
889     while (!IsNull (&DriverHealthList, Link)) {\r
890       //\r
891       // Got the item relative node in the List\r
892       //\r
893       if (Index == (gCallbackKey - DRIVER_HEALTH_KEY_OFFSET)) { \r
894         DriverHealthInfo = DEVICE_MANAGER_HEALTH_INFO_FROM_LINK (Link);\r
895         //\r
896         // Process the driver's healthy status for the specify module\r
897         //\r
898         ProcessSingleControllerHealth (\r
899           DriverHealthInfo->DriverHealth,\r
900           DriverHealthInfo->ControllerHandle,      \r
901           DriverHealthInfo->ChildHandle,\r
902           DriverHealthInfo->HealthStatus,\r
903           &(DriverHealthInfo->MessageList),\r
904           DriverHealthInfo->HiiHandle\r
905        );  \r
906        break;\r
907       }\r
908       Index++;\r
909       Link = GetNextNode (&DriverHealthList, Link);\r
910     }\r
911 \r
912     if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {\r
913       EnableResetRequired ();\r
914     }\r
915     \r
916     //\r
917     // Force return to the form of Driver Health in Device Manager \r
918     //\r
919     gCallbackKey = DRIVER_HEALTH_RETURN_KEY;\r
920   }\r
921 \r
922   //\r
923   // Repair the whole platform\r
924   //\r
925   if (gCallbackKey == DRIVER_HEALTH_REPAIR_ALL_KEY) {\r
926     ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
927     \r
928     PlatformRepairAll (&DriverHealthList);\r
929 \r
930     gCallbackKey = DRIVER_HEALTH_RETURN_KEY;\r
931   }\r
932    \r
933   //\r
934   // Cleanup dynamic created strings in HII database by reinstall the packagelist\r
935   //\r
936   \r
937   HiiRemovePackages (HiiHandle);\r
938 \r
939   gDeviceManagerPrivate.DriverHealthHiiHandle = HiiAddPackages (\r
940                                                   &mDriverHealthGuid,\r
941                                                   gDeviceManagerPrivate.DriverHealthHandle,\r
942                                                   DriverHealthVfrBin,\r
943                                                   BdsDxeStrings,\r
944                                                   NULL\r
945                                                   );\r
946   if (gDeviceManagerPrivate.DriverHealthHiiHandle == NULL) {\r
947     Status = EFI_OUT_OF_RESOURCES;\r
948   } else {\r
949     Status = EFI_SUCCESS;\r
950   }\r
951   //\r
952   // Free driver health info list\r
953   //\r
954   while (!IsListEmpty (&DriverHealthList)) {\r
955 \r
956     Link = GetFirstNode(&DriverHealthList);\r
957     DriverHealthInfo = DEVICE_MANAGER_HEALTH_INFO_FROM_LINK (Link);\r
958     RemoveEntryList (Link);\r
959 \r
960     if (DriverHealthInfo->MessageList != NULL) {\r
961       FreePool(DriverHealthInfo->MessageList);\r
962       FreePool (DriverHealthInfo);\r
963     }   \r
964   }\r
965 \r
966   HiiFreeOpCodeHandle (StartOpCodeHandle);\r
967   HiiFreeOpCodeHandle (EndOpCodeHandle); \r
968   HiiFreeOpCodeHandle (StartOpCodeHandleRepair);\r
969   HiiFreeOpCodeHandle (EndOpCodeHandleRepair); \r
970 \r
971   if (gCallbackKey == DRIVER_HEALTH_RETURN_KEY) {\r
972     //\r
973     // Force return to Driver Health Form\r
974     //\r
975     gCallbackKey = DEVICE_MANAGER_KEY_DRIVER_HEALTH;\r
976     CallDriverHealth ();\r
977   }\r
978 }\r
979 \r
980 \r
981 /*\r
982   Check the Driver Health status of a single controller and try to process it if not healthy.\r
983 \r
984   This function called by CheckAllControllersHealthStatus () function in order to process a specify\r
985   contoller's health state.\r
986 \r
987   @param DriverHealth       A pointer to the EFI_DRIVER_HEALTH_PROTOCOL instance.\r
988   @param ControllerHandle   The class guid specifies which form set will be displayed.\r
989   @param ChildHandle        The handle of the child controller to retrieve the health \r
990                            status on.  This is an optional parameter that may be NULL. \r
991   @param HealthStatus       The health status of the controller.\r
992   @param MessageList        An array of warning or error messages associated \r
993                            with the controller specified by ControllerHandle and \r
994                            ChildHandle.  This is an optional parameter that may be NULL.\r
995   @param FormHiiHandle      The HII handle for an HII form associated with the \r
996                            controller specified by ControllerHandle and ChildHandle.\r
997 \r
998   @retval EFI_INVALID_PARAMETER   HealthStatus or DriverHealth is NULL.\r
999   @retval HealthStatus            The Health status of specify controller.\r
1000   @retval EFI_OUT_OF_RESOURCES    The list of Driver Health Protocol handles can not be retrieved.\r
1001   @retval EFI_NOT_FOUND           No controller in the platform install Driver Health Protocol.\r
1002   @retval EFI_SUCCESS             The Health related operation has been taken successfully.\r
1003 \r
1004 */\r
1005 EFI_STATUS\r
1006 EFIAPI\r
1007 GetSingleControllerHealthStatus (\r
1008   IN OUT LIST_ENTRY                   *DriverHealthList,\r
1009   IN EFI_HANDLE                       DriverHandle,\r
1010   IN EFI_HANDLE                       ControllerHandle,  OPTIONAL\r
1011   IN EFI_HANDLE                       ChildHandle,       OPTIONAL\r
1012   IN EFI_DRIVER_HEALTH_PROTOCOL       *DriverHealth,\r
1013   IN EFI_DRIVER_HEALTH_STATUS         *HealthStatus\r
1014   )\r
1015 {\r
1016   EFI_STATUS                     Status;\r
1017   EFI_DRIVER_HEALTH_HII_MESSAGE  *MessageList;\r
1018   EFI_HII_HANDLE                 FormHiiHandle;\r
1019   DRIVER_HEALTH_INFO             *DriverHealthInfo;\r
1020 \r
1021   if (HealthStatus == NULL) {\r
1022     //\r
1023     // If HealthStatus is NULL, then return EFI_INVALID_PARAMETER\r
1024     //\r
1025     return EFI_INVALID_PARAMETER;\r
1026   }\r
1027 \r
1028   //\r
1029   // Assume the HealthStatus is healthy\r
1030   //\r
1031   *HealthStatus = EfiDriverHealthStatusHealthy;\r
1032 \r
1033   if (DriverHealth == NULL) {\r
1034     //\r
1035     // If DriverHealth is NULL, then return EFI_INVALID_PARAMETER\r
1036     //\r
1037     return EFI_INVALID_PARAMETER;\r
1038   }\r
1039 \r
1040   if (ControllerHandle == NULL) {\r
1041     //\r
1042     // If ControllerHandle is NULL, the return the cumulative health status of the driver\r
1043     //\r
1044     Status = DriverHealth->GetHealthStatus (DriverHealth, NULL, NULL, HealthStatus, NULL, NULL);\r
1045     if (*HealthStatus == EfiDriverHealthStatusHealthy) {\r
1046       //\r
1047       // Add the driver health related information into the list\r
1048       //\r
1049       DriverHealthInfo = AllocateZeroPool (sizeof (DRIVER_HEALTH_INFO));\r
1050       if (DriverHealthInfo == NULL) {\r
1051         return EFI_OUT_OF_RESOURCES;\r
1052       }\r
1053 \r
1054       DriverHealthInfo->Signature          = DEVICE_MANAGER_DRIVER_HEALTH_INFO_SIGNATURE;\r
1055       DriverHealthInfo->DriverHandle       = DriverHandle;\r
1056       DriverHealthInfo->ControllerHandle   = NULL;\r
1057       DriverHealthInfo->ChildHandle        = NULL;\r
1058       DriverHealthInfo->HiiHandle          = NULL;\r
1059       DriverHealthInfo->DriverHealth       = DriverHealth;\r
1060       DriverHealthInfo->MessageList        = NULL;\r
1061       DriverHealthInfo->HealthStatus       = *HealthStatus;\r
1062 \r
1063       InsertTailList (DriverHealthList, &DriverHealthInfo->Link);\r
1064     }\r
1065     return Status;\r
1066   }\r
1067 \r
1068   MessageList   = NULL;\r
1069   FormHiiHandle = NULL;\r
1070 \r
1071   //\r
1072   // Collect the health status with the optional HII message list\r
1073   //\r
1074   Status = DriverHealth->GetHealthStatus (DriverHealth, ControllerHandle, ChildHandle, HealthStatus, &MessageList, &FormHiiHandle);\r
1075 \r
1076   if (EFI_ERROR (Status)) {\r
1077     //\r
1078     // If the health status could not be retrieved, then return immediately\r
1079     //\r
1080     return Status;\r
1081   }\r
1082 \r
1083   //\r
1084   // Add the driver health related information into the list\r
1085   //\r
1086   DriverHealthInfo = AllocateZeroPool (sizeof (DRIVER_HEALTH_INFO));\r
1087   if (DriverHealthInfo == NULL) {\r
1088     return EFI_OUT_OF_RESOURCES;\r
1089   }\r
1090 \r
1091   DriverHealthInfo->Signature          = DEVICE_MANAGER_DRIVER_HEALTH_INFO_SIGNATURE; \r
1092   DriverHealthInfo->DriverHandle       = DriverHandle;\r
1093   DriverHealthInfo->ControllerHandle   = ControllerHandle;\r
1094   DriverHealthInfo->ChildHandle        = ChildHandle;\r
1095   DriverHealthInfo->HiiHandle          = FormHiiHandle;\r
1096   DriverHealthInfo->DriverHealth       = DriverHealth;\r
1097   DriverHealthInfo->MessageList        = MessageList;\r
1098   DriverHealthInfo->HealthStatus       = *HealthStatus;\r
1099 \r
1100   InsertTailList (DriverHealthList, &DriverHealthInfo->Link);\r
1101 \r
1102   return EFI_SUCCESS;\r
1103 }\r
1104 \r
1105 /**\r
1106   Collects all the EFI Driver Health Protocols currently present in the EFI Handle Database, \r
1107   and queries each EFI Driver Health Protocol to determine if one or more of the controllers \r
1108   managed by each EFI Driver Health Protocol instance are not healthy.  \r
1109 \r
1110   @param DriverHealthList   A Pointer to the list contain all of the platform driver health\r
1111                             information. \r
1112 \r
1113   @retval    EFI_NOT_FOUND         No controller in the platform install Driver Health Protocol.\r
1114   @retval    EFI_SUCCESS           All the controllers in the platform are healthy.\r
1115   @retval    EFI_OUT_OF_RESOURCES  The list of Driver Health Protocol handles can not be retrieved.\r
1116 \r
1117 **/\r
1118 EFI_STATUS\r
1119 GetAllControllersHealthStatus (\r
1120   IN OUT LIST_ENTRY  *DriverHealthList\r
1121   )\r
1122 {\r
1123   EFI_STATUS                 Status; \r
1124   UINTN                      NumHandles;\r
1125   EFI_HANDLE                 *DriverHealthHandles;\r
1126   EFI_DRIVER_HEALTH_PROTOCOL *DriverHealth;\r
1127   EFI_DRIVER_HEALTH_STATUS   HealthStatus;\r
1128   UINTN                      DriverHealthIndex;\r
1129   EFI_HANDLE                 *Handles;\r
1130   UINTN                      HandleCount;\r
1131   UINTN                      ControllerIndex;\r
1132   UINTN                      ChildIndex;\r
1133  \r
1134   //\r
1135   // Initialize local variables\r
1136   //\r
1137   Handles                 = NULL;\r
1138   DriverHealthHandles     = NULL;\r
1139   NumHandles              = 0;\r
1140   HandleCount             = 0;\r
1141 \r
1142   HealthStatus = EfiDriverHealthStatusHealthy;\r
1143 \r
1144   Status = gBS->LocateHandleBuffer (\r
1145                   ByProtocol,\r
1146                   &gEfiDriverHealthProtocolGuid,\r
1147                   NULL,\r
1148                   &NumHandles,\r
1149                   &DriverHealthHandles\r
1150                   );\r
1151 \r
1152   if (Status == EFI_NOT_FOUND || NumHandles == 0) {\r
1153     //\r
1154     // If there are no Driver Health Protocols handles, then return EFI_NOT_FOUND\r
1155     //\r
1156     return EFI_NOT_FOUND;\r
1157   }\r
1158 \r
1159   if (EFI_ERROR (Status) || DriverHealthHandles == NULL) {\r
1160     //\r
1161     // If the list of Driver Health Protocol handles can not be retrieved, then \r
1162     // return EFI_OUT_OF_RESOURCES\r
1163     //\r
1164     return EFI_OUT_OF_RESOURCES;\r
1165   }\r
1166 \r
1167   //\r
1168   // Check the health status of all controllers in the platform\r
1169   // Start by looping through all the Driver Health Protocol handles in the handle database\r
1170   //\r
1171   for (DriverHealthIndex = 0; DriverHealthIndex < NumHandles; DriverHealthIndex++) {\r
1172     //\r
1173     // Skip NULL Driver Health Protocol handles\r
1174     //\r
1175     if (DriverHealthHandles[DriverHealthIndex] == NULL) {\r
1176       continue;\r
1177     }\r
1178 \r
1179     //\r
1180     // Retrieve the Driver Health Protocol from DriverHandle\r
1181     //\r
1182     Status = gBS->HandleProtocol ( \r
1183                     DriverHealthHandles[DriverHealthIndex],\r
1184                     &gEfiDriverHealthProtocolGuid,\r
1185                     (VOID **)&DriverHealth\r
1186                     );\r
1187     if (EFI_ERROR (Status)) {\r
1188       //\r
1189       // If the Driver Health Protocol can not be retrieved, then skip to the next\r
1190       // Driver Health Protocol handle\r
1191       //\r
1192       continue;\r
1193     }\r
1194 \r
1195     //\r
1196     // Check the health of all the controllers managed by a Driver Health Protocol handle\r
1197     //\r
1198     Status = GetSingleControllerHealthStatus (DriverHealthList, DriverHealthHandles[DriverHealthIndex], NULL, NULL, DriverHealth, &HealthStatus);\r
1199 \r
1200     //\r
1201     // If Status is an error code, then the health information could not be retrieved, so assume healthy\r
1202     // and skip to the next Driver Health Protocol handle\r
1203     //\r
1204     if (EFI_ERROR (Status)) {\r
1205       continue;\r
1206     }\r
1207 \r
1208     //\r
1209     // If all the controllers managed by this Driver Health Protocol are healthy, then skip to the next \r
1210     // Driver Health Protocol handle\r
1211     //\r
1212     if (HealthStatus == EfiDriverHealthStatusHealthy) {\r
1213       continue;\r
1214     }\r
1215 \r
1216     //\r
1217     // See if the list of all handles in the handle database has been retrieved\r
1218     //\r
1219     //\r
1220     if (Handles == NULL) {\r
1221       //\r
1222       // Retrieve the list of all handles from the handle database\r
1223       //\r
1224       Status = gBS->LocateHandleBuffer (\r
1225         AllHandles,\r
1226         NULL,\r
1227         NULL,\r
1228         &HandleCount,\r
1229         &Handles\r
1230         );\r
1231       if (EFI_ERROR (Status) || Handles == NULL) {\r
1232         //\r
1233         // If all the handles in the handle database can not be retrieved, then \r
1234         // return EFI_OUT_OF_RESOURCES\r
1235         //\r
1236         Status = EFI_OUT_OF_RESOURCES;\r
1237         goto Done;\r
1238       }\r
1239     }\r
1240     //\r
1241     // Loop through all the controller handles in the handle database\r
1242     //\r
1243     for (ControllerIndex = 0; ControllerIndex < HandleCount; ControllerIndex++) {\r
1244       //\r
1245       // Skip NULL controller handles\r
1246       //\r
1247       if (Handles[ControllerIndex] == NULL) {\r
1248         continue;\r
1249       }\r
1250 \r
1251       Status = GetSingleControllerHealthStatus (DriverHealthList, DriverHealthHandles[DriverHealthIndex], Handles[ControllerIndex], NULL, DriverHealth, &HealthStatus);\r
1252       if (EFI_ERROR (Status)) {\r
1253         //\r
1254         // If Status is an error code, then the health information could not be retrieved, so assume healthy\r
1255         //\r
1256         HealthStatus = EfiDriverHealthStatusHealthy;\r
1257       }\r
1258 \r
1259       //\r
1260       // If CheckHealthSingleController() returned an error on a terminal state, then do not check the health of child controllers\r
1261       //\r
1262       if (EFI_ERROR (Status)) {\r
1263         continue;\r
1264       }\r
1265 \r
1266       //\r
1267       // Loop through all the child handles in the handle database\r
1268       //\r
1269       for (ChildIndex = 0; ChildIndex < HandleCount; ChildIndex++) {\r
1270         //\r
1271         // Skip NULL child handles\r
1272         //\r
1273         if (Handles[ChildIndex] == NULL) {\r
1274           continue;\r
1275         }\r
1276 \r
1277         Status = GetSingleControllerHealthStatus (DriverHealthList, DriverHealthHandles[DriverHealthIndex], Handles[ControllerIndex], Handles[ChildIndex], DriverHealth, &HealthStatus);\r
1278         if (EFI_ERROR (Status)) {\r
1279           //\r
1280           // If Status is an error code, then the health information could not be retrieved, so assume healthy\r
1281           //\r
1282           HealthStatus = EfiDriverHealthStatusHealthy;\r
1283         }\r
1284 \r
1285         //\r
1286         // If CheckHealthSingleController() returned an error on a terminal state, then skip to the next child\r
1287         //\r
1288         if (EFI_ERROR (Status)) {\r
1289           continue;\r
1290         }\r
1291       }\r
1292     }\r
1293   }\r
1294 \r
1295   Status = EFI_SUCCESS;\r
1296 \r
1297 Done:\r
1298   if (Handles != NULL) {\r
1299     gBS->FreePool (Handles);\r
1300   }\r
1301   if (DriverHealthHandles != NULL) {\r
1302     gBS->FreePool (DriverHealthHandles);\r
1303   }\r
1304 \r
1305   return Status;\r
1306 }\r
1307 \r
1308 \r
1309 /*\r
1310   Check the healthy status of the platform, this function will return immediately while found one driver \r
1311   in the platform are not healthy.\r
1312 \r
1313   @retval FALSE      at least one driver in the platform are not healthy.\r
1314   @retval TRUE       No controller install Driver Health Protocol,\r
1315                      or all controllers in the platform are in healthy status.\r
1316 */\r
1317 BOOLEAN\r
1318 PlaformHealthStatusCheck (\r
1319   VOID\r
1320   )\r
1321 {\r
1322   EFI_DRIVER_HEALTH_STATUS          HealthStatus;\r
1323   EFI_STATUS                        Status;\r
1324   UINTN                             Index;\r
1325   UINTN                             NoHandles;\r
1326   EFI_HANDLE                        *DriverHealthHandles;\r
1327   EFI_DRIVER_HEALTH_PROTOCOL        *DriverHealth;\r
1328   BOOLEAN                           AllHealthy;\r
1329 \r
1330   //\r
1331   // Initialize local variables\r
1332   //\r
1333   DriverHealthHandles = NULL;\r
1334   DriverHealth        = NULL;\r
1335 \r
1336   HealthStatus = EfiDriverHealthStatusHealthy;\r
1337 \r
1338   Status = gBS->LocateHandleBuffer (\r
1339                   ByProtocol,\r
1340                   &gEfiDriverHealthProtocolGuid,\r
1341                   NULL,\r
1342                   &NoHandles,\r
1343                   &DriverHealthHandles\r
1344                   );\r
1345   //\r
1346   // There are no handles match the search for Driver Health Protocol has been installed.\r
1347   //\r
1348   if (Status == EFI_NOT_FOUND) {\r
1349     return TRUE;\r
1350   }\r
1351   //\r
1352   // Assume all modules are healthy.\r
1353   // \r
1354   AllHealthy = TRUE;\r
1355 \r
1356   //\r
1357   // Found one or more Handles.\r
1358   //\r
1359   if (!EFI_ERROR (Status)) {    \r
1360     for (Index = 0; Index < NoHandles; Index++) {\r
1361       Status = gBS->HandleProtocol (\r
1362                       DriverHealthHandles[Index],\r
1363                       &gEfiDriverHealthProtocolGuid,\r
1364                       (VOID **) &DriverHealth\r
1365                       );\r
1366       if (!EFI_ERROR (Status)) {\r
1367         Status = DriverHealth->GetHealthStatus (\r
1368                                  DriverHealth,\r
1369                                  NULL,\r
1370                                  NULL,\r
1371                                  &HealthStatus,\r
1372                                  NULL,\r
1373                                  NULL\r
1374                                  );\r
1375       }\r
1376       //\r
1377       // Get the healthy status of the module\r
1378       //\r
1379       if (!EFI_ERROR (Status)) {\r
1380          if (HealthStatus != EfiDriverHealthStatusHealthy) {\r
1381            //\r
1382            // Return immediately one driver's status not in healthy.\r
1383            //\r
1384            return FALSE;         \r
1385          }\r
1386       }\r
1387     }\r
1388   }\r
1389   return AllHealthy;\r
1390 }\r
1391 \r
1392 /**\r
1393   Processes a single controller using the EFI Driver Health Protocol associated with \r
1394   that controller. This algorithm continues to query the GetHealthStatus() service until\r
1395   one of the legal terminal states of the EFI Driver Health Protocol is reached. This may \r
1396   require the processing of HII Messages, HII Form, and invocation of repair operations.\r
1397 \r
1398   @param DriverHealth       A pointer to the EFI_DRIVER_HEALTH_PROTOCOL instance.\r
1399   @param ControllerHandle   The class guid specifies which form set will be displayed.\r
1400   @param ChildHandle        The handle of the child controller to retrieve the health \r
1401                             status on.  This is an optional parameter that may be NULL. \r
1402   @param HealthStatus       The health status of the controller.\r
1403   @param MessageList        An array of warning or error messages associated \r
1404                             with the controller specified by ControllerHandle and \r
1405                             ChildHandle.  This is an optional parameter that may be NULL.\r
1406   @param FormHiiHandle      The HII handle for an HII form associated with the \r
1407                             controller specified by ControllerHandle and ChildHandle.\r
1408 **/\r
1409 VOID\r
1410 ProcessSingleControllerHealth (\r
1411     IN  EFI_DRIVER_HEALTH_PROTOCOL         *DriverHealth,\r
1412     IN  EFI_HANDLE                         ControllerHandle, OPTIONAL\r
1413     IN  EFI_HANDLE                         ChildHandle,      OPTIONAL\r
1414     IN  EFI_DRIVER_HEALTH_STATUS           HealthStatus,\r
1415     IN  EFI_DRIVER_HEALTH_HII_MESSAGE      **MessageList,    OPTIONAL\r
1416     IN  EFI_HII_HANDLE                     FormHiiHandle\r
1417   )\r
1418 {\r
1419   EFI_STATUS                         Status;\r
1420   EFI_DRIVER_HEALTH_STATUS           LocalHealthStatus;\r
1421   \r
1422   LocalHealthStatus = HealthStatus;\r
1423   //\r
1424   // If the module need to be repaired or reconfiguration,  will process it until\r
1425   // reach a terminal status. The status from EfiDriverHealthStatusRepairRequired after repair \r
1426   // will be in (Health, Failed, Configuration Required).\r
1427   //\r
1428   while( LocalHealthStatus == EfiDriverHealthStatusConfigurationRequired ||\r
1429          LocalHealthStatus == EfiDriverHealthStatusRepairRequired) {\r
1430 \r
1431     if (LocalHealthStatus == EfiDriverHealthStatusRepairRequired) {\r
1432       Status = DriverHealth->Repair (\r
1433                                DriverHealth,\r
1434                                ControllerHandle,\r
1435                                ChildHandle,\r
1436                                (EFI_DRIVER_HEALTH_REPAIR_PROGRESS_NOTIFY) RepairNotify\r
1437                                );\r
1438     }\r
1439     //\r
1440     // Via a form of the driver need to do configuration provided to process of status in \r
1441     // EfiDriverHealthStatusConfigurationRequired. The status after configuration should be in\r
1442     // (Healthy, Reboot Required, Failed, Reconnect Required, Repair Required).   \r
1443     //\r
1444     if (LocalHealthStatus == EfiDriverHealthStatusConfigurationRequired) {\r
1445       Status = gFormBrowser2->SendForm (\r
1446                                 gFormBrowser2,\r
1447                                 &FormHiiHandle,\r
1448                                 1,\r
1449                                 &gEfiHiiDriverHealthFormsetGuid,\r
1450                                 0,\r
1451                                 NULL,\r
1452                                 NULL\r
1453                                 );\r
1454       ASSERT( !EFI_ERROR (Status));\r
1455     }\r
1456 \r
1457     Status = DriverHealth->GetHealthStatus (\r
1458                               DriverHealth,\r
1459                               ControllerHandle,\r
1460                               ChildHandle,\r
1461                               &LocalHealthStatus,\r
1462                               NULL,\r
1463                               &FormHiiHandle\r
1464                               );\r
1465    ASSERT_EFI_ERROR (Status);\r
1466 \r
1467    if (*MessageList != NULL) {\r
1468       ProcessMessages (*MessageList);\r
1469    }  \r
1470   }\r
1471   \r
1472   //\r
1473   // Health status in {Healthy, Failed} may also have Messages need to process\r
1474   //\r
1475   if (LocalHealthStatus == EfiDriverHealthStatusHealthy || LocalHealthStatus == EfiDriverHealthStatusFailed) {\r
1476     if (*MessageList != NULL) {\r
1477       ProcessMessages (*MessageList);\r
1478     }\r
1479   }\r
1480   //\r
1481   // Check for RebootRequired or ReconnectRequired\r
1482   //\r
1483   if (LocalHealthStatus == EfiDriverHealthStatusRebootRequired) {\r
1484     gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);\r
1485   }\r
1486   \r
1487   //\r
1488   // Do reconnect if need.\r
1489   //\r
1490   if (LocalHealthStatus == EfiDriverHealthStatusReconnectRequired) {\r
1491     Status = gBS->DisconnectController (ControllerHandle, NULL, NULL);\r
1492     if (EFI_ERROR (Status)) {\r
1493         //\r
1494         // Disconnect failed.  Need to promote reconnect to a reboot.\r
1495         //\r
1496         gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);\r
1497     }\r
1498     gBS->ConnectController (ControllerHandle, NULL, NULL, TRUE);\r
1499   }\r
1500 }\r
1501 \r
1502 \r
1503 /**\r
1504   Platform specific notification function for controller repair operations.\r
1505 \r
1506   If the driver for a controller support the Driver Health Protocol and the\r
1507   current state of the controller is EfiDriverHealthStatusRepairRequired then\r
1508   when the Repair() service of the Driver Health Protocol is called, this \r
1509   platform specific notification function can display the progress of the repair\r
1510   operation.  Some platforms may choose to not display anything, other may choose\r
1511   to show the percentage complete on text consoles, and other may choose to render\r
1512   a progress bar on text and graphical consoles.\r
1513 \r
1514   This function displays the percentage of the repair operation that has been\r
1515   completed on text consoles.  The percentage is Value / Limit * 100%.\r
1516   \r
1517   @param  Value               Value in the range 0..Limit the the repair has completed..\r
1518   @param  Limit               The maximum value of Value\r
1519 \r
1520 **/\r
1521 VOID\r
1522 RepairNotify (\r
1523   IN  UINTN Value,\r
1524   IN  UINTN Limit\r
1525   )\r
1526 {\r
1527   UINTN Percent;\r
1528 \r
1529   if (Limit  == 0) {\r
1530     Print(L"Repair Progress Undefined\n\r");\r
1531   } else {\r
1532     Percent = Value * 100 / Limit;\r
1533     Print(L"Repair Progress = %3d%%\n\r", Percent);\r
1534   }\r
1535 }\r
1536 \r
1537 /**\r
1538   Processes a set of messages returned by the GetHealthStatus ()\r
1539   service of the EFI Driver Health Protocol\r
1540 \r
1541   @param    MessageList  The MessageList point to messages need to processed.  \r
1542 \r
1543 **/\r
1544 VOID\r
1545 ProcessMessages (\r
1546   IN  EFI_DRIVER_HEALTH_HII_MESSAGE      *MessageList\r
1547   )\r
1548 {\r
1549   UINTN                           MessageIndex;\r
1550   EFI_STRING                      MessageString;\r
1551 \r
1552   for (MessageIndex = 0;\r
1553        MessageList[MessageIndex].HiiHandle != NULL;\r
1554        MessageIndex++) {\r
1555 \r
1556     MessageString = HiiGetString (\r
1557                         MessageList[MessageIndex].HiiHandle,\r
1558                         MessageList[MessageIndex].StringId,\r
1559                         NULL\r
1560                         );\r
1561     if (MessageString != NULL) {\r
1562       //\r
1563       // User can customize the output. Just simply print out the MessageString like below. \r
1564       // Also can use the HiiHandle to display message on the front page.\r
1565       // \r
1566       // Print(L"%s\n",MessageString);\r
1567       // gBS->Stall (100000);\r
1568     }\r
1569   }\r
1570 \r
1571 }\r
1572 \r
1573 /*\r
1574   Repair the whole platform.\r
1575 \r
1576   This function is the main entry for user choose "Repair All" in the front page.\r
1577   It will try to do recovery job till all the driver health protocol installed modules \r
1578   reach a terminal state.\r
1579 \r
1580   @param DriverHealthList   A Pointer to the list contain all of the platform driver health\r
1581                             information.\r
1582 \r
1583 */\r
1584 VOID\r
1585 PlatformRepairAll (\r
1586   IN LIST_ENTRY  *DriverHealthList\r
1587   )\r
1588\r
1589   DRIVER_HEALTH_INFO          *DriverHealthInfo;\r
1590   LIST_ENTRY                  *Link;\r
1591 \r
1592   ASSERT (DriverHealthList != NULL);\r
1593 \r
1594   Link = GetFirstNode (DriverHealthList);\r
1595 \r
1596   while (!IsNull (DriverHealthList, Link)) {   \r
1597     DriverHealthInfo = DEVICE_MANAGER_HEALTH_INFO_FROM_LINK (Link);\r
1598     //\r
1599     // Do driver health status operation by each link node\r
1600     //\r
1601     ASSERT (DriverHealthInfo != NULL);\r
1602 \r
1603     ProcessSingleControllerHealth ( \r
1604         DriverHealthInfo->DriverHealth,\r
1605         DriverHealthInfo->ControllerHandle,\r
1606         DriverHealthInfo->ChildHandle,\r
1607         DriverHealthInfo->HealthStatus,\r
1608         &(DriverHealthInfo->MessageList),\r
1609         DriverHealthInfo->HiiHandle\r
1610         );\r
1611 \r
1612     Link = GetNextNode (DriverHealthList, Link);\r
1613   }\r
1614 }\r
1615 \r
1616 /**\r
1617 \r
1618   Select the best matching language according to front page policy for best user experience. \r
1619   \r
1620   This function supports both ISO 639-2 and RFC 4646 language codes, but language \r
1621   code types may not be mixed in a single call to this function. \r
1622 \r
1623   @param  SupportedLanguages   A pointer to a Null-terminated ASCII string that\r
1624                                contains a set of language codes in the format \r
1625                                specified by Iso639Language.\r
1626   @param  Iso639Language       If TRUE, then all language codes are assumed to be\r
1627                                in ISO 639-2 format.  If FALSE, then all language\r
1628                                codes are assumed to be in RFC 4646 language format.\r
1629 \r
1630   @retval NULL                 The best matching language could not be found in SupportedLanguages.\r
1631   @retval NULL                 There are not enough resources available to return the best matching \r
1632                                language.\r
1633   @retval Other                A pointer to a Null-terminated ASCII string that is the best matching \r
1634                                language in SupportedLanguages.\r
1635 **/\r
1636 CHAR8 *\r
1637 DriverHealthSelectBestLanguage (\r
1638   IN CHAR8        *SupportedLanguages,\r
1639   IN BOOLEAN      Iso639Language\r
1640   )\r
1641 {\r
1642   CHAR8           *LanguageVariable;\r
1643   CHAR8           *BestLanguage;\r
1644 \r
1645   LanguageVariable =  GetEfiGlobalVariable (Iso639Language ? L"Lang" : L"PlatformLang");\r
1646 \r
1647   BestLanguage = GetBestLanguage(\r
1648                    SupportedLanguages,\r
1649                    Iso639Language,\r
1650                    (LanguageVariable != NULL) ? LanguageVariable : "",\r
1651                    Iso639Language ? "eng" : "en-US",\r
1652                    NULL\r
1653                    );\r
1654   if (LanguageVariable != NULL) {\r
1655     FreePool (LanguageVariable);\r
1656   }\r
1657 \r
1658   return BestLanguage;\r
1659 }\r
1660 \r
1661 \r
1662 \r
1663 /**\r
1664 \r
1665   This is an internal worker function to get the Component Name (2) protocol interface\r
1666   and the language it supports.\r
1667 \r
1668   @param  ProtocolGuid         A pointer to an EFI_GUID. It points to Component Name (2) protocol GUID.\r
1669   @param  DriverBindingHandle  The handle on which the Component Name (2) protocol instance is retrieved.\r
1670   @param  ComponentName        A pointer to the Component Name (2) protocol interface.\r
1671   @param  SupportedLanguage    The best suitable language that matches the SupportedLangues interface for the \r
1672                                located Component Name (2) instance.\r
1673 \r
1674   @param  EFI_SUCCESS          The Component Name (2) protocol instance is successfully located and we find\r
1675                                the best matching language it support.\r
1676   @param  EFI_UNSUPPORTED      The input Language is not supported by the Component Name (2) protocol.\r
1677   @param  Other                Some error occurs when locating Component Name (2) protocol instance or finding\r
1678                                the supported language.\r
1679 \r
1680 **/\r
1681 EFI_STATUS\r
1682 GetComponentNameWorker (\r
1683   IN  EFI_GUID                    *ProtocolGuid,\r
1684   IN  EFI_HANDLE                  DriverBindingHandle,\r
1685   OUT EFI_COMPONENT_NAME_PROTOCOL **ComponentName,\r
1686   OUT CHAR8                       **SupportedLanguage\r
1687   )\r
1688 {\r
1689   EFI_STATUS                      Status;\r
1690 \r
1691   //\r
1692   // Locate Component Name (2) protocol on the driver binging handle.\r
1693   //\r
1694   Status = gBS->OpenProtocol (\r
1695                  DriverBindingHandle,\r
1696                  ProtocolGuid,\r
1697                  (VOID **) ComponentName,\r
1698                  NULL,\r
1699                  NULL,\r
1700                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1701                  );\r
1702   if (EFI_ERROR (Status)) {\r
1703     return Status;\r
1704   }\r
1705 \r
1706   //\r
1707   // Apply shell policy to select the best language.\r
1708   //\r
1709   *SupportedLanguage = DriverHealthSelectBestLanguage (\r
1710                          (*ComponentName)->SupportedLanguages,\r
1711                          (BOOLEAN) (ProtocolGuid == &gEfiComponentNameProtocolGuid)\r
1712                          );\r
1713   if (*SupportedLanguage == NULL) {\r
1714     Status = EFI_UNSUPPORTED;\r
1715   }\r
1716 \r
1717   return Status;\r
1718 }\r
1719 \r
1720 /**\r
1721 \r
1722   This is an internal worker function to get driver name from Component Name (2) protocol interface.\r
1723 \r
1724 \r
1725   @param  ProtocolGuid         A pointer to an EFI_GUID. It points to Component Name (2) protocol GUID.\r
1726   @param  DriverBindingHandle  The handle on which the Component Name (2) protocol instance is retrieved.\r
1727   @param  DriverName           A pointer to the Unicode string to return. This Unicode string is the name\r
1728                                of the driver specified by This.\r
1729 \r
1730   @retval EFI_SUCCESS          The driver name is successfully retrieved from Component Name (2) protocol\r
1731                                interface.\r
1732   @retval Other                The driver name cannot be retrieved from Component Name (2) protocol\r
1733                                interface.\r
1734 \r
1735 **/\r
1736 EFI_STATUS\r
1737 GetDriverNameWorker (\r
1738   IN  EFI_GUID    *ProtocolGuid,\r
1739   IN  EFI_HANDLE  DriverBindingHandle,\r
1740   OUT CHAR16      **DriverName\r
1741   )\r
1742 {\r
1743   EFI_STATUS                     Status;\r
1744   CHAR8                          *BestLanguage;\r
1745   EFI_COMPONENT_NAME_PROTOCOL    *ComponentName;\r
1746 \r
1747   //\r
1748   // Retrieve Component Name (2) protocol instance on the driver binding handle and \r
1749   // find the best language this instance supports. \r
1750   //\r
1751   Status = GetComponentNameWorker (\r
1752              ProtocolGuid,\r
1753              DriverBindingHandle,\r
1754              &ComponentName,\r
1755              &BestLanguage\r
1756              );\r
1757   if (EFI_ERROR (Status)) {\r
1758     return Status;\r
1759   }\r
1760  \r
1761   //\r
1762   // Get the driver name from Component Name (2) protocol instance on the driver binging handle.\r
1763   //\r
1764   Status = ComponentName->GetDriverName (\r
1765                             ComponentName,\r
1766                             BestLanguage,\r
1767                             DriverName\r
1768                             );\r
1769   FreePool (BestLanguage);\r
1770  \r
1771   return Status;\r
1772 }\r
1773 \r
1774 /**\r
1775 \r
1776   This function gets driver name from Component Name 2 protocol interface and Component Name protocol interface\r
1777   in turn. It first tries UEFI 2.0 Component Name 2 protocol interface and try to get the driver name.\r
1778   If the attempt fails, it then gets the driver name from EFI 1.1 Component Name protocol for backward\r
1779   compatibility support. \r
1780 \r
1781   @param  DriverBindingHandle  The handle on which the Component Name (2) protocol instance is retrieved.\r
1782   @param  DriverName           A pointer to the Unicode string to return. This Unicode string is the name\r
1783                                of the driver specified by This.\r
1784 \r
1785   @retval EFI_SUCCESS          The driver name is successfully retrieved from Component Name (2) protocol\r
1786                                interface.\r
1787   @retval Other                The driver name cannot be retrieved from Component Name (2) protocol\r
1788                                interface.\r
1789 \r
1790 **/\r
1791 EFI_STATUS\r
1792 DriverHealthGetDriverName (\r
1793   IN  EFI_HANDLE  DriverBindingHandle,\r
1794   OUT CHAR16      **DriverName\r
1795   )\r
1796 {\r
1797   EFI_STATUS      Status;\r
1798 \r
1799   //\r
1800   // Get driver name from UEFI 2.0 Component Name 2 protocol interface.\r
1801   //\r
1802   Status = GetDriverNameWorker (&gEfiComponentName2ProtocolGuid, DriverBindingHandle, DriverName);\r
1803   if (EFI_ERROR (Status)) {\r
1804     //\r
1805     // If it fails to get the driver name from Component Name protocol interface, we should fall back on\r
1806     // EFI 1.1 Component Name protocol interface.\r
1807     //\r
1808     Status = GetDriverNameWorker (&gEfiComponentNameProtocolGuid, DriverBindingHandle, DriverName);\r
1809   }\r
1810 \r
1811   return Status;\r
1812 }\r
1813 \r
1814 \r
1815 \r
1816 /**\r
1817   This function gets controller name from Component Name 2 protocol interface and Component Name protocol interface\r
1818   in turn. It first tries UEFI 2.0 Component Name 2 protocol interface and try to get the controller name.\r
1819   If the attempt fails, it then gets the controller name from EFI 1.1 Component Name protocol for backward\r
1820   compatibility support. \r
1821 \r
1822   @param  ProtocolGuid         A pointer to an EFI_GUID. It points to Component Name (2) protocol GUID.\r
1823   @param  DriverBindingHandle  The handle on which the Component Name (2) protocol instance is retrieved.\r
1824   @param  ControllerHandle     The handle of a controller that the driver specified by This is managing.\r
1825                                This handle specifies the controller whose name is to be returned.\r
1826   @param  ChildHandle          The handle of the child controller to retrieve the name of. This is an\r
1827                                optional parameter that may be NULL. It will be NULL for device drivers.\r
1828                                It will also be NULL for bus drivers that attempt to retrieve the name\r
1829                                of the bus controller. It will not be NULL for a bus driver that attempts\r
1830                                to retrieve the name of a child controller.\r
1831   @param  ControllerName       A pointer to the Unicode string to return. This Unicode string\r
1832                                is the name of the controller specified by ControllerHandle and ChildHandle.\r
1833 \r
1834   @retval  EFI_SUCCESS         The controller name is successfully retrieved from Component Name (2) protocol\r
1835                                interface.\r
1836   @retval  Other               The controller name cannot be retrieved from Component Name (2) protocol.\r
1837 \r
1838 **/\r
1839 EFI_STATUS\r
1840 GetControllerNameWorker (\r
1841   IN  EFI_GUID    *ProtocolGuid,\r
1842   IN  EFI_HANDLE  DriverBindingHandle,\r
1843   IN  EFI_HANDLE  ControllerHandle,\r
1844   IN  EFI_HANDLE  ChildHandle,\r
1845   OUT CHAR16      **ControllerName\r
1846   )\r
1847 {\r
1848   EFI_STATUS                     Status;\r
1849   CHAR8                          *BestLanguage;\r
1850   EFI_COMPONENT_NAME_PROTOCOL    *ComponentName;\r
1851 \r
1852   //\r
1853   // Retrieve Component Name (2) protocol instance on the driver binding handle and \r
1854   // find the best language this instance supports. \r
1855   //\r
1856   Status = GetComponentNameWorker (\r
1857              ProtocolGuid,\r
1858              DriverBindingHandle,\r
1859              &ComponentName,\r
1860              &BestLanguage\r
1861              );\r
1862   if (EFI_ERROR (Status)) {\r
1863     return Status;\r
1864   }\r
1865 \r
1866   //\r
1867   // Get the controller name from Component Name (2) protocol instance on the driver binging handle.\r
1868   //\r
1869   Status = ComponentName->GetControllerName (\r
1870                             ComponentName,\r
1871                             ControllerHandle,\r
1872                             ChildHandle,\r
1873                             BestLanguage,\r
1874                             ControllerName\r
1875                             );\r
1876   FreePool (BestLanguage);\r
1877 \r
1878   return Status;\r
1879 }\r
1880 \r
1881 /**\r
1882 \r
1883   This function gets controller name from Component Name 2 protocol interface and Component Name protocol interface\r
1884   in turn. It first tries UEFI 2.0 Component Name 2 protocol interface and try to get the controller name. \r
1885   If the attempt fails, it then gets the controller name from EFI 1.1 Component Name protocol for backward\r
1886   compatibility support. \r
1887 \r
1888   @param  DriverBindingHandle  The handle on which the Component Name (2) protocol instance is retrieved.\r
1889   @param  ControllerHandle     The handle of a controller that the driver specified by This is managing.\r
1890                                This handle specifies the controller whose name is to be returned.\r
1891   @param  ChildHandle          The handle of the child controller to retrieve the name of. This is an\r
1892                                optional parameter that may be NULL. It will be NULL for device drivers.\r
1893                                It will also be NULL for bus drivers that attempt to retrieve the name\r
1894                                of the bus controller. It will not be NULL for a bus driver that attempts\r
1895                                to retrieve the name of a child controller.\r
1896   @param  Language             An ASCII string that represents the language command line option.\r
1897   @param  ControllerName       A pointer to the Unicode string to return. This Unicode string\r
1898                                is the name of the controller specified by ControllerHandle and ChildHandle.\r
1899 \r
1900   @retval EFI_SUCCESS          The controller name is successfully retrieved from Component Name (2) protocol\r
1901                                interface.\r
1902   @retval Other                The controller name cannot be retrieved from Component Name (2) protocol.\r
1903 \r
1904 **/\r
1905 EFI_STATUS\r
1906 DriverHealthGetControllerName (\r
1907   IN  EFI_HANDLE  DriverBindingHandle,\r
1908   IN  EFI_HANDLE  ControllerHandle,\r
1909   IN  EFI_HANDLE  ChildHandle,\r
1910   OUT CHAR16      **ControllerName\r
1911   )\r
1912 {\r
1913   EFI_STATUS      Status;\r
1914 \r
1915   //\r
1916   // Get controller name from UEFI 2.0 Component Name 2 protocol interface.\r
1917   //\r
1918   Status = GetControllerNameWorker (\r
1919              &gEfiComponentName2ProtocolGuid,\r
1920              DriverBindingHandle,\r
1921              ControllerHandle,\r
1922              ChildHandle,\r
1923              ControllerName\r
1924              );\r
1925   if (EFI_ERROR (Status)) {\r
1926     //\r
1927     // If it fails to get the controller name from Component Name protocol interface, we should fall back on\r
1928     // EFI 1.1 Component Name protocol interface.\r
1929     //\r
1930     Status = GetControllerNameWorker (\r
1931                &gEfiComponentNameProtocolGuid,\r
1932                DriverBindingHandle,\r
1933                ControllerHandle,\r
1934                ChildHandle,\r
1935                ControllerName\r
1936                );\r
1937   }\r
1938 \r
1939   return Status;\r
1940 }\r