]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManager.c
866df574f6e7c7550a55478d82b9004948e855d6
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / BdsDxe / DeviceMngr / DeviceManager.c
1 /** @file
2 The platform device manager reference implementation
3
4 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "DeviceManager.h"
16
17 DEVICE_MANAGER_CALLBACK_DATA gDeviceManagerPrivate = {
18 DEVICE_MANAGER_CALLBACK_DATA_SIGNATURE,
19 NULL,
20 NULL,
21 NULL,
22 NULL,
23 {
24 FakeExtractConfig,
25 FakeRouteConfig,
26 DeviceManagerCallback
27 },
28 {
29 FakeExtractConfig,
30 FakeRouteConfig,
31 DriverHealthCallback
32 }
33 };
34
35 #define MAX_MAC_ADDRESS_NODE_LIST_LEN 10
36
37 //
38 // Which Mac Address string is select
39 // it will decide what menu need to show in the NETWORK_DEVICE_FORM_ID form.
40 //
41 EFI_STRING mSelectedMacAddrString;
42
43 //
44 // Which form Id need to be show.
45 //
46 EFI_FORM_ID mNextShowFormId = DEVICE_MANAGER_FORM_ID;
47
48 //
49 // The Mac Address show in the NETWORK_DEVICE_LIST_FORM_ID
50 //
51 MAC_ADDRESS_NODE_LIST mMacDeviceList;
52
53 DEVICE_MANAGER_MENU_ITEM mDeviceManagerMenuItemTable[] = {
54 { STRING_TOKEN (STR_DISK_DEVICE), EFI_DISK_DEVICE_CLASS },
55 { STRING_TOKEN (STR_VIDEO_DEVICE), EFI_VIDEO_DEVICE_CLASS },
56 { STRING_TOKEN (STR_NETWORK_DEVICE), EFI_NETWORK_DEVICE_CLASS },
57 { STRING_TOKEN (STR_INPUT_DEVICE), EFI_INPUT_DEVICE_CLASS },
58 { STRING_TOKEN (STR_ON_BOARD_DEVICE), EFI_ON_BOARD_DEVICE_CLASS },
59 { STRING_TOKEN (STR_OTHER_DEVICE), EFI_OTHER_DEVICE_CLASS }
60 };
61
62 HII_VENDOR_DEVICE_PATH mDeviceManagerHiiVendorDevicePath = {
63 {
64 {
65 HARDWARE_DEVICE_PATH,
66 HW_VENDOR_DP,
67 {
68 (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
69 (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
70 }
71 },
72 DEVICE_MANAGER_FORMSET_GUID
73 },
74 {
75 END_DEVICE_PATH_TYPE,
76 END_ENTIRE_DEVICE_PATH_SUBTYPE,
77 {
78 (UINT8) (END_DEVICE_PATH_LENGTH),
79 (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
80 }
81 }
82 };
83
84 HII_VENDOR_DEVICE_PATH mDriverHealthHiiVendorDevicePath = {
85 {
86 {
87 HARDWARE_DEVICE_PATH,
88 HW_VENDOR_DP,
89 {
90 (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
91 (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
92 }
93 },
94 DRIVER_HEALTH_FORMSET_GUID
95 },
96 {
97 END_DEVICE_PATH_TYPE,
98 END_ENTIRE_DEVICE_PATH_SUBTYPE,
99 {
100 (UINT8) (END_DEVICE_PATH_LENGTH),
101 (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
102 }
103 }
104 };
105
106 /**
107 This function is invoked if user selected a interactive opcode from Device Manager's
108 Formset. The decision by user is saved to gCallbackKey for later processing. If
109 user set VBIOS, the new value is saved to EFI variable.
110
111 @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
112 @param Action Specifies the type of action taken by the browser.
113 @param QuestionId A unique value which is sent to the original exporting driver
114 so that it can identify the type of data to expect.
115 @param Type The type of value for the question.
116 @param Value A pointer to the data being sent to the original exporting driver.
117 @param ActionRequest On return, points to the action requested by the callback function.
118
119 @retval EFI_SUCCESS The callback successfully handled the action.
120 @retval EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
121
122 **/
123 EFI_STATUS
124 EFIAPI
125 DeviceManagerCallback (
126 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
127 IN EFI_BROWSER_ACTION Action,
128 IN EFI_QUESTION_ID QuestionId,
129 IN UINT8 Type,
130 IN EFI_IFR_TYPE_VALUE *Value,
131 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
132 )
133 {
134 UINTN CurIndex;
135
136 if (Action != EFI_BROWSER_ACTION_CHANGING) {
137 //
138 // All other action return unsupported.
139 //
140 return EFI_UNSUPPORTED;
141 }
142
143 if (Value == NULL) {
144 return EFI_INVALID_PARAMETER;
145 }
146
147 gCallbackKey = QuestionId;
148 if ((QuestionId < MAX_KEY_SECTION_LEN + NETWORK_DEVICE_LIST_KEY_OFFSET) && (QuestionId >= NETWORK_DEVICE_LIST_KEY_OFFSET)) {
149 //
150 // If user select the mac address, need to record mac address string to support next form show.
151 //
152 for (CurIndex = 0; CurIndex < mMacDeviceList.CurListLen; CurIndex ++) {
153 if (mMacDeviceList.NodeList[CurIndex].QuestionId == QuestionId) {
154 mSelectedMacAddrString = HiiGetString (gDeviceManagerPrivate.HiiHandle, mMacDeviceList.NodeList[CurIndex].PromptId, NULL);
155 }
156 }
157 }
158
159 return EFI_SUCCESS;
160 }
161
162 /**
163
164 This function registers HII packages to HII database.
165
166 @retval EFI_SUCCESS HII packages for the Device Manager were registered successfully.
167 @retval EFI_OUT_OF_RESOURCES HII packages for the Device Manager failed to be registered.
168
169 **/
170 EFI_STATUS
171 InitializeDeviceManager (
172 VOID
173 )
174 {
175 EFI_STATUS Status;
176
177 //
178 // Install Device Path Protocol and Config Access protocol to driver handle
179 //
180 Status = gBS->InstallMultipleProtocolInterfaces (
181 &gDeviceManagerPrivate.DriverHandle,
182 &gEfiDevicePathProtocolGuid,
183 &mDeviceManagerHiiVendorDevicePath,
184 &gEfiHiiConfigAccessProtocolGuid,
185 &gDeviceManagerPrivate.ConfigAccess,
186 NULL
187 );
188 ASSERT_EFI_ERROR (Status);
189
190 Status = gBS->InstallMultipleProtocolInterfaces (
191 &gDeviceManagerPrivate.DriverHealthHandle,
192 &gEfiDevicePathProtocolGuid,
193 &mDriverHealthHiiVendorDevicePath,
194 &gEfiHiiConfigAccessProtocolGuid,
195 &gDeviceManagerPrivate.DriverHealthConfigAccess,
196 NULL
197 );
198 ASSERT_EFI_ERROR (Status);
199
200 mMacDeviceList.CurListLen = 0;
201 mMacDeviceList.MaxListLen = 0;
202
203 return Status;
204 }
205
206 /**
207 Extract the displayed formset for given HII handle and class guid.
208
209 @param Handle The HII handle.
210 @param SetupClassGuid The class guid specifies which form set will be displayed.
211 @param SkipCount Skip some formsets which has processed before.
212 @param FormSetTitle Formset title string.
213 @param FormSetHelp Formset help string.
214 @param FormSetGuid Return the formset guid for this formset.
215
216 @retval TRUE The formset for given HII handle will be displayed.
217 @return FALSE The formset for given HII handle will not be displayed.
218
219 **/
220 BOOLEAN
221 ExtractDisplayedHiiFormFromHiiHandle (
222 IN EFI_HII_HANDLE Handle,
223 IN EFI_GUID *SetupClassGuid,
224 IN UINTN SkipCount,
225 OUT EFI_STRING_ID *FormSetTitle,
226 OUT EFI_STRING_ID *FormSetHelp,
227 OUT EFI_GUID **FormSetGuid
228 )
229 {
230 EFI_STATUS Status;
231 UINTN BufferSize;
232 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
233 UINT8 *Package;
234 UINT8 *OpCodeData;
235 UINT32 Offset;
236 UINT32 Offset2;
237 UINT32 PackageListLength;
238 EFI_HII_PACKAGE_HEADER PackageHeader;
239 EFI_GUID *ClassGuid;
240 UINT8 ClassGuidNum;
241
242 ASSERT (Handle != NULL);
243 ASSERT (SetupClassGuid != NULL);
244 ASSERT (FormSetTitle != NULL);
245 ASSERT (FormSetHelp != NULL);
246
247 *FormSetTitle = 0;
248 *FormSetHelp = 0;
249 ClassGuidNum = 0;
250 ClassGuid = NULL;
251
252 //
253 // Get HII PackageList
254 //
255 BufferSize = 0;
256 HiiPackageList = NULL;
257 Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &BufferSize, HiiPackageList);
258 //
259 // Handle is a invalid handle. Check if Handle is corrupted.
260 //
261 ASSERT (Status != EFI_NOT_FOUND);
262 //
263 // The return status should always be EFI_BUFFER_TOO_SMALL as input buffer's size is 0.
264 //
265 ASSERT (Status == EFI_BUFFER_TOO_SMALL);
266
267 HiiPackageList = AllocatePool (BufferSize);
268 ASSERT (HiiPackageList != NULL);
269
270 Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &BufferSize, HiiPackageList);
271 if (EFI_ERROR (Status)) {
272 return FALSE;
273 }
274
275 //
276 // Get Form package from this HII package List
277 //
278 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
279 Offset2 = 0;
280 PackageListLength = ReadUnaligned32 (&HiiPackageList->PackageLength);
281
282 while (Offset < PackageListLength) {
283 Package = ((UINT8 *) HiiPackageList) + Offset;
284 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
285
286 if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
287 //
288 // Search FormSet Opcode in this Form Package
289 //
290 Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
291 while (Offset2 < PackageHeader.Length) {
292 OpCodeData = Package + Offset2;
293 Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
294
295 if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
296 if (SkipCount != 0) {
297 SkipCount --;
298 continue;
299 }
300
301 if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {
302 //
303 // Find FormSet OpCode
304 //
305 ClassGuidNum = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
306 ClassGuid = (EFI_GUID *) (VOID *)(OpCodeData + sizeof (EFI_IFR_FORM_SET));
307 while (ClassGuidNum-- > 0) {
308 if (CompareGuid (SetupClassGuid, ClassGuid)) {
309 CopyMem (FormSetTitle, &((EFI_IFR_FORM_SET *) OpCodeData)->FormSetTitle, sizeof (EFI_STRING_ID));
310 CopyMem (FormSetHelp, &((EFI_IFR_FORM_SET *) OpCodeData)->Help, sizeof (EFI_STRING_ID));
311 *FormSetGuid = AllocateCopyPool (sizeof (EFI_GUID), &((EFI_IFR_FORM_SET *) OpCodeData)->Guid);
312 ASSERT (*FormSetGuid != NULL);
313 FreePool (HiiPackageList);
314 return TRUE;
315 }
316 ClassGuid ++;
317 }
318 } else {
319 CopyMem (FormSetTitle, &((EFI_IFR_FORM_SET *) OpCodeData)->FormSetTitle, sizeof (EFI_STRING_ID));
320 CopyMem (FormSetHelp, &((EFI_IFR_FORM_SET *) OpCodeData)->Help, sizeof (EFI_STRING_ID));
321 *FormSetGuid = AllocateCopyPool (sizeof (EFI_GUID), &((EFI_IFR_FORM_SET *) OpCodeData)->Guid);
322 ASSERT (*FormSetGuid != NULL);
323 FreePool (HiiPackageList);
324 return TRUE;
325 }
326 }
327 }
328 }
329
330 //
331 // Go to next package
332 //
333 Offset += PackageHeader.Length;
334 }
335
336 FreePool (HiiPackageList);
337
338 return FALSE;
339 }
340
341 /**
342 Get the mac address string from the device path.
343 if the device path has the vlan, get the vanid also.
344
345 @param MacAddressNode Device path begin with mac address
346 @param PBuffer Output string buffer contain mac address.
347
348 **/
349 BOOLEAN
350 GetMacAddressString(
351 IN MAC_ADDR_DEVICE_PATH *MacAddressNode,
352 OUT CHAR16 **PBuffer
353 )
354 {
355 UINTN HwAddressSize;
356 UINTN Index;
357 UINT8 *HwAddress;
358 EFI_DEVICE_PATH_PROTOCOL *Node;
359 UINT16 VlanId;
360 CHAR16 *String;
361 UINTN BufferLen;
362
363 VlanId = 0;
364 String = NULL;
365 ASSERT(MacAddressNode != NULL);
366
367 HwAddressSize = sizeof (EFI_MAC_ADDRESS);
368 if (MacAddressNode->IfType == 0x01 || MacAddressNode->IfType == 0x00) {
369 HwAddressSize = 6;
370 }
371
372 //
373 // The output format is MAC:XX:XX:XX:...\XXXX
374 // The size is the Number size + ":" size + Vlan size(\XXXX) + End
375 //
376 BufferLen = (4 + 2 * HwAddressSize + (HwAddressSize - 1) + 5 + 1) * sizeof (CHAR16);
377 String = AllocateZeroPool (BufferLen);
378 if (String == NULL) {
379 return FALSE;
380 }
381
382 *PBuffer = String;
383 StrCpy(String, L"MAC:");
384 String += 4;
385
386 //
387 // Convert the MAC address into a unicode string.
388 //
389 HwAddress = &MacAddressNode->MacAddress.Addr[0];
390 for (Index = 0; Index < HwAddressSize; Index++) {
391 String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(HwAddress++), 2);
392 if (Index < HwAddressSize - 1) {
393 *String++ = L':';
394 }
395 }
396
397 //
398 // If VLAN is configured, it will need extra 5 characters like "\0005".
399 // Plus one unicode character for the null-terminator.
400 //
401 Node = (EFI_DEVICE_PATH_PROTOCOL *)MacAddressNode;
402 while (!IsDevicePathEnd (Node)) {
403 if (Node->Type == MESSAGING_DEVICE_PATH && Node->SubType == MSG_VLAN_DP) {
404 VlanId = ((VLAN_DEVICE_PATH *) Node)->VlanId;
405 }
406 Node = NextDevicePathNode (Node);
407 }
408
409 if (VlanId != 0) {
410 *String++ = L'\\';
411 String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, VlanId, 4);
412 }
413
414 //
415 // Null terminate the Unicode string
416 //
417 *String = L'\0';
418
419 return TRUE;
420 }
421
422 /**
423 Save question id and prompt id to the mac device list.
424 If the same mac address has saved yet, no need to add more.
425
426 @param MacAddrString Mac address string.
427
428 @retval EFI_SUCCESS Add the item is successful.
429 @return Other values if failed to Add the item.
430 **/
431 BOOLEAN
432 AddIdToMacDeviceList (
433 IN EFI_STRING MacAddrString
434 )
435 {
436 MENU_INFO_ITEM *TempDeviceList;
437 UINTN Index;
438 EFI_STRING StoredString;
439 EFI_STRING_ID PromptId;
440 EFI_HII_HANDLE HiiHandle;
441
442 HiiHandle = gDeviceManagerPrivate.HiiHandle;
443 TempDeviceList = NULL;
444
445 for (Index = 0; Index < mMacDeviceList.CurListLen; Index ++) {
446 StoredString = HiiGetString (HiiHandle, mMacDeviceList.NodeList[Index].PromptId, NULL);
447 if (StoredString == NULL) {
448 return FALSE;
449 }
450
451 //
452 // Already has save the same mac address to the list.
453 //
454 if (StrCmp (MacAddrString, StoredString) == 0) {
455 return FALSE;
456 }
457 }
458
459 PromptId = HiiSetString(HiiHandle, 0, MacAddrString, NULL);
460 //
461 // If not in the list, save it.
462 //
463 if (mMacDeviceList.MaxListLen > mMacDeviceList.CurListLen + 1) {
464 mMacDeviceList.NodeList[mMacDeviceList.CurListLen].PromptId = PromptId;
465 mMacDeviceList.NodeList[mMacDeviceList.CurListLen].QuestionId = (EFI_QUESTION_ID) (mMacDeviceList.CurListLen + NETWORK_DEVICE_LIST_KEY_OFFSET);
466 } else {
467 mMacDeviceList.MaxListLen += MAX_MAC_ADDRESS_NODE_LIST_LEN;
468 if (mMacDeviceList.CurListLen != 0) {
469 TempDeviceList = (MENU_INFO_ITEM *)AllocateCopyPool (sizeof (MENU_INFO_ITEM) * mMacDeviceList.MaxListLen, (VOID *)mMacDeviceList.NodeList);
470 } else {
471 TempDeviceList = (MENU_INFO_ITEM *)AllocatePool (sizeof (MENU_INFO_ITEM) * mMacDeviceList.MaxListLen);
472 }
473
474 if (TempDeviceList == NULL) {
475 return FALSE;
476 }
477 TempDeviceList[mMacDeviceList.CurListLen].PromptId = PromptId;
478 TempDeviceList[mMacDeviceList.CurListLen].QuestionId = (EFI_QUESTION_ID) (mMacDeviceList.CurListLen + NETWORK_DEVICE_LIST_KEY_OFFSET);
479
480 if (mMacDeviceList.CurListLen > 0) {
481 FreePool(mMacDeviceList.NodeList);
482 }
483
484 mMacDeviceList.NodeList = TempDeviceList;
485 }
486 mMacDeviceList.CurListLen ++;
487
488 return TRUE;
489 }
490
491 /**
492 Check the devcie path, try to find whether it has mac address path.
493
494 In this function, first need to check whether this path has mac address path.
495 second, when the mac address device path has find, also need to deicide whether
496 need to add this mac address relate info to the menu.
497
498 @param *Node Input device which need to be check.
499 @param *NeedAddItem Whether need to add the menu in the network device list.
500
501 @retval TRUE Has mac address device path.
502 @retval FALSE NOT Has mac address device path.
503
504 **/
505 BOOLEAN
506 IsMacAddressDevicePath (
507 IN VOID *Node,
508 OUT BOOLEAN *NeedAddItem
509 )
510 {
511 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
512 CHAR16 *Buffer;
513 BOOLEAN ReturnVal;
514
515 ASSERT (Node != NULL);
516 *NeedAddItem = FALSE;
517 ReturnVal = FALSE;
518 Buffer = NULL;
519
520 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Node;
521
522 //
523 // find the partition device path node
524 //
525 while (!IsDevicePathEnd (DevicePath)) {
526 if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
527 (DevicePathSubType (DevicePath) == MSG_MAC_ADDR_DP)) {
528 ReturnVal = TRUE;
529
530 if (DEVICE_MANAGER_FORM_ID == mNextShowFormId) {
531 *NeedAddItem = TRUE;
532 break;
533 }
534
535 if (!GetMacAddressString((MAC_ADDR_DEVICE_PATH*)DevicePath, &Buffer)) {
536 break;
537 }
538
539 if (NETWORK_DEVICE_FORM_ID == mNextShowFormId) {
540 if (StrCmp (Buffer, mSelectedMacAddrString) == 0) {
541 *NeedAddItem = TRUE;
542 }
543 break;
544 }
545
546 if (NETWORK_DEVICE_LIST_FORM_ID == mNextShowFormId) {
547 //
548 // Same handle may has two network child handle, so the questionid
549 // has the offset of SAME_HANDLE_KEY_OFFSET.
550 //
551 if (AddIdToMacDeviceList (Buffer)) {
552 *NeedAddItem = TRUE;
553 }
554 break;
555 }
556 }
557 DevicePath = NextDevicePathNode (DevicePath);
558 }
559
560 if (Buffer != NULL) {
561 FreePool (Buffer);
562 }
563
564 return ReturnVal;
565 }
566
567 /**
568 Check to see if the device path is for the network device.
569
570 @param Handle The HII handle which include the mac address device path.
571 @param ItemCount The new add Mac address item count.
572
573 @retval TRUE Need to add new item in the menu.
574 @return FALSE Do not need to add the menu about the network.
575
576 **/
577 BOOLEAN
578 IsNeedAddNetworkMenu (
579 IN EFI_HII_HANDLE Handle,
580 OUT UINTN *ItemCount
581 )
582 {
583 EFI_STATUS Status;
584 UINTN EntryCount;
585 UINTN Index;
586 EFI_HANDLE DriverHandle;
587 EFI_HANDLE ControllerHandle;
588 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
589 EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
590 EFI_DEVICE_PATH_PROTOCOL *ChildDevicePath;
591 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
592 BOOLEAN IsNeedAdd;
593
594 IsNeedAdd = FALSE;
595 OpenInfoBuffer = NULL;
596 if ((Handle == NULL) || (ItemCount == NULL)) {
597 return FALSE;
598 }
599 *ItemCount = 0;
600
601 Status = gHiiDatabase->GetPackageListHandle (gHiiDatabase, Handle, &DriverHandle);
602 if (EFI_ERROR (Status)) {
603 return FALSE;
604 }
605 //
606 // Get the device path by the got Driver handle .
607 //
608 Status = gBS->HandleProtocol (DriverHandle, &gEfiDevicePathProtocolGuid, (VOID **) &DevicePath);
609 if (EFI_ERROR (Status)) {
610 return FALSE;
611 }
612 TmpDevicePath = DevicePath;
613
614 //
615 // Check whether this device path include mac address device path.
616 // If this path has mac address path, get the value whether need
617 // add this info to the menu and return.
618 // Else check more about the child handle devcie path.
619 //
620 if (IsMacAddressDevicePath(TmpDevicePath, &IsNeedAdd)) {
621 if ((NETWORK_DEVICE_LIST_FORM_ID == mNextShowFormId) && IsNeedAdd) {
622 (*ItemCount) = 1;
623 }
624 return IsNeedAdd;
625 }
626
627 //
628 // Search whether this path is the controller path, not he child handle path.
629 // And the child handle has the network devcie connected.
630 //
631 TmpDevicePath = DevicePath;
632 Status = gBS->LocateDevicePath(&gEfiDevicePathProtocolGuid, &TmpDevicePath, &ControllerHandle);
633 if (EFI_ERROR (Status)) {
634 return FALSE;
635 }
636
637 if (!IsDevicePathEnd (TmpDevicePath)) {
638 return FALSE;
639 }
640
641 //
642 // Retrieve the list of agents that are consuming the specific protocol
643 // on ControllerHandle.
644 // The buffer point by OpenInfoBuffer need be free at this function.
645 //
646 Status = gBS->OpenProtocolInformation (
647 ControllerHandle,
648 &gEfiPciIoProtocolGuid,
649 &OpenInfoBuffer,
650 &EntryCount
651 );
652 if (EFI_ERROR (Status)) {
653 return FALSE;
654 }
655
656 //
657 // Inspect if ChildHandle is one of the agents.
658 //
659 Status = EFI_UNSUPPORTED;
660 for (Index = 0; Index < EntryCount; Index++) {
661 //
662 // Query all the children created by the controller handle's driver
663 //
664 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
665 Status = gBS->OpenProtocol (
666 OpenInfoBuffer[Index].ControllerHandle,
667 &gEfiDevicePathProtocolGuid,
668 (VOID **) &ChildDevicePath,
669 NULL,
670 NULL,
671 EFI_OPEN_PROTOCOL_GET_PROTOCOL
672 );
673 if (EFI_ERROR (Status)) {
674 continue;
675 }
676
677 //
678 // Check whether this device path include mac address device path.
679 //
680 if (!IsMacAddressDevicePath(ChildDevicePath, &IsNeedAdd)) {
681 //
682 // If this path not has mac address path, check the other.
683 //
684 continue;
685 } else {
686 //
687 // If need to update the NETWORK_DEVICE_LIST_FORM, try to get more.
688 //
689 if ((NETWORK_DEVICE_LIST_FORM_ID == mNextShowFormId)) {
690 if (IsNeedAdd) {
691 (*ItemCount) += 1;
692 }
693 continue;
694 } else {
695 //
696 // If need to update other form, return whether need to add to the menu.
697 //
698 goto Done;
699 }
700 }
701 }
702 }
703
704 Done:
705 if (OpenInfoBuffer != NULL) {
706 FreePool (OpenInfoBuffer);
707 }
708 return IsNeedAdd;
709 }
710
711 /**
712 Get HiiHandle total number.
713
714 @param HiiHandles The input HiiHandle array.
715
716 @retval the Hiihandle count.
717
718 **/
719 UINTN
720 GetHiiHandleCount (
721 IN EFI_HII_HANDLE *HiiHandles
722 )
723 {
724 UINTN Index;
725
726 for (Index = 0; HiiHandles[Index] != NULL; Index++) {
727 }
728
729 return Index;
730 }
731
732 /**
733 Insert the new HiiHandle + FormsetGuid at the NewPair[InsertOffset].
734
735 @param HiiHandles The input HiiHandle array.
736 @param GuidLists The input form set guid lists.
737 @param ArrayCount The input array count, new array will be arraycount + 1 size.
738 @param Offset The current used HiiHandle's Offset.
739 @param FormSetGuid The new found formset guid.
740
741 **/
742 VOID
743 AdjustArrayData (
744 IN OUT EFI_HII_HANDLE **HiiHandles,
745 IN OUT EFI_GUID ***GuidLists,
746 IN UINTN ArrayCount,
747 IN UINTN Offset,
748 IN EFI_GUID *FormSetGuid
749 )
750 {
751 EFI_HII_HANDLE *NewHiiHandles;
752 EFI_GUID **NewGuidLists;
753
754 //
755 // +2 means include the new HiiHandle and the last empty NULL pointer.
756 //
757 NewHiiHandles = AllocateZeroPool ((ArrayCount + 2) * sizeof (EFI_HII_HANDLE));
758 ASSERT (NewHiiHandles != NULL);
759
760 CopyMem (NewHiiHandles, *HiiHandles, Offset * sizeof (EFI_HII_HANDLE));
761 NewHiiHandles[Offset] = NewHiiHandles[Offset - 1];
762 CopyMem (NewHiiHandles + Offset + 1, *HiiHandles + Offset, (ArrayCount - Offset) * sizeof (EFI_HII_HANDLE));
763
764 NewGuidLists = AllocateZeroPool ((ArrayCount + 2) * sizeof (EFI_GUID *));
765 ASSERT (NewGuidLists != NULL);
766
767 CopyMem (NewGuidLists, *GuidLists, Offset * sizeof (EFI_GUID *));
768 NewGuidLists[Offset] = FormSetGuid;
769
770 FreePool (*HiiHandles);
771 *HiiHandles = NewHiiHandles;
772 FreePool (*GuidLists);
773 *GuidLists = NewGuidLists;
774 }
775
776 /**
777 Call the browser and display the device manager to allow user
778 to configure the platform.
779
780 This function create the dynamic content for device manager. It includes
781 section header for all class of devices, one-of opcode to set VBIOS.
782
783 @retval EFI_SUCCESS Operation is successful.
784 @return Other values if failed to clean up the dynamic content from HII
785 database.
786
787 **/
788 EFI_STATUS
789 CallDeviceManager (
790 VOID
791 )
792 {
793 EFI_STATUS Status;
794 UINTN Index;
795 EFI_STRING String;
796 EFI_STRING_ID Token;
797 EFI_STRING_ID TokenHelp;
798 EFI_HII_HANDLE *HiiHandles;
799 EFI_HII_HANDLE HiiHandle;
800 EFI_STRING_ID FormSetTitle;
801 EFI_STRING_ID FormSetHelp;
802 EFI_BROWSER_ACTION_REQUEST ActionRequest;
803 VOID *StartOpCodeHandle;
804 VOID *EndOpCodeHandle;
805 EFI_IFR_GUID_LABEL *StartLabel;
806 EFI_IFR_GUID_LABEL *EndLabel;
807 UINTN NumHandles;
808 EFI_HANDLE *DriverHealthHandles;
809 BOOLEAN AddNetworkMenu;
810 UINTN AddItemCount;
811 UINTN NewStringLen;
812 EFI_STRING NewStringTitle;
813 EFI_GUID **GuidLists;
814 UINTN HandleNum;
815 UINTN SkipCount;
816 EFI_GUID *FormSetGuid;
817
818 GuidLists = NULL;
819 HiiHandles = NULL;
820 Status = EFI_SUCCESS;
821 gCallbackKey = 0;
822 NumHandles = 0;
823 DriverHealthHandles = NULL;
824 AddNetworkMenu = FALSE;
825 AddItemCount = 0;
826 SkipCount = 0;
827 FormSetGuid = NULL;
828
829 //
830 // Connect all prior to entering the platform setup menu.
831 //
832 if (!gConnectAllHappened) {
833 BdsLibConnectAllDriversToAllControllers ();
834 gConnectAllHappened = TRUE;
835 }
836
837 HiiHandle = gDeviceManagerPrivate.HiiHandle;
838 if (HiiHandle == NULL) {
839 //
840 // Publish our HII data.
841 //
842 HiiHandle = HiiAddPackages (
843 &gDeviceManagerFormSetGuid,
844 gDeviceManagerPrivate.DriverHandle,
845 DeviceManagerVfrBin,
846 BdsDxeStrings,
847 NULL
848 );
849 if (HiiHandle == NULL) {
850 return EFI_OUT_OF_RESOURCES;
851 }
852
853 gDeviceManagerPrivate.HiiHandle = HiiHandle;
854 }
855
856 //
857 // If need show the Network device list form, clear the old save list first.
858 //
859 if ((mNextShowFormId == NETWORK_DEVICE_LIST_FORM_ID) && (mMacDeviceList.CurListLen > 0)) {
860 mMacDeviceList.CurListLen = 0;
861 }
862
863 //
864 // Update the network device form titile.
865 //
866 if (mNextShowFormId == NETWORK_DEVICE_FORM_ID) {
867 String = HiiGetString (HiiHandle, STRING_TOKEN (STR_FORM_NETWORK_DEVICE_TITLE), NULL);
868 NewStringLen = StrLen(mSelectedMacAddrString) * 2;
869 NewStringLen += (StrLen(String) + 2) * 2;
870 NewStringTitle = AllocatePool (NewStringLen);
871 UnicodeSPrint (NewStringTitle, NewStringLen, L"%s %s", String, mSelectedMacAddrString);
872 HiiSetString (HiiHandle, STRING_TOKEN (STR_FORM_NETWORK_DEVICE_TITLE), NewStringTitle, NULL);
873 FreePool (String);
874 FreePool (NewStringTitle);
875 }
876
877 //
878 // Allocate space for creation of UpdateData Buffer
879 //
880 StartOpCodeHandle = HiiAllocateOpCodeHandle ();
881 ASSERT (StartOpCodeHandle != NULL);
882
883 EndOpCodeHandle = HiiAllocateOpCodeHandle ();
884 ASSERT (EndOpCodeHandle != NULL);
885
886 //
887 // Create Hii Extend Label OpCode as the start opcode
888 //
889 StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
890 StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
891 //
892 // According to the next show Form id(mNextShowFormId) to decide which form need to update.
893 //
894 StartLabel->Number = (UINT16) (LABEL_FORM_ID_OFFSET + mNextShowFormId);
895
896 //
897 // Create Hii Extend Label OpCode as the end opcode
898 //
899 EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
900 EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
901 EndLabel->Number = LABEL_END;
902
903 //
904 // Get all the Hii handles
905 //
906 HiiHandles = HiiGetHiiHandles (NULL);
907 ASSERT (HiiHandles != NULL);
908
909 HandleNum = GetHiiHandleCount (HiiHandles);
910 GuidLists = AllocateZeroPool ((HandleNum + 1) * sizeof (EFI_GUID *));
911 ASSERT (GuidLists != NULL);
912
913 //
914 // Search for formset of each class type
915 //
916 for (Index = 0; HiiHandles[Index] != NULL; Index++) {
917 //
918 // The QuestionId in the form which will call the driver form has this asssumption.
919 // QuestionId = Handle Index + NETWORK_DEVICE_LIST_KEY_OFFSET;
920 // Different QuestionId at least has the section of NETWORK_DEVICE_LIST_KEY_OFFSET.
921 //
922 ASSERT(Index < MAX_KEY_SECTION_LEN);
923
924 if (!ExtractDisplayedHiiFormFromHiiHandle (HiiHandles[Index], &gEfiHiiPlatformSetupFormsetGuid, SkipCount, &FormSetTitle, &FormSetHelp, &FormSetGuid)) {
925 SkipCount = 0;
926 continue;
927 }
928
929 //
930 // One HiiHandle has more than one formset can be shown,
931 // Insert a new pair of HiiHandle + Guid to the HiiHandles and GuidLists list.
932 //
933 if (SkipCount > 0) {
934 AdjustArrayData (&HiiHandles, &GuidLists, HandleNum, Index + 1, FormSetGuid);
935 HandleNum ++;
936 Index ++;
937 }
938
939 String = HiiGetString (HiiHandles[Index], FormSetTitle, NULL);
940 if (String == NULL) {
941 String = HiiGetString (HiiHandle, STR_MISSING_STRING, NULL);
942 ASSERT (String != NULL);
943 }
944 Token = HiiSetString (HiiHandle, 0, String, NULL);
945 FreePool (String);
946
947 String = HiiGetString (HiiHandles[Index], FormSetHelp, NULL);
948 if (String == NULL) {
949 String = HiiGetString (HiiHandle, STR_MISSING_STRING, NULL);
950 ASSERT (String != NULL);
951 }
952 TokenHelp = HiiSetString (HiiHandle, 0, String, NULL);
953 FreePool (String);
954
955 //
956 // Network device process
957 //
958 if (IsNeedAddNetworkMenu (HiiHandles[Index], &AddItemCount)) {
959 if (mNextShowFormId == DEVICE_MANAGER_FORM_ID) {
960 //
961 // Only show one menu item "Network Config" in the device manger form.
962 //
963 if (!AddNetworkMenu) {
964 AddNetworkMenu = TRUE;
965 HiiCreateGotoOpCode (
966 StartOpCodeHandle,
967 INVALID_FORM_ID,
968 STRING_TOKEN (STR_FORM_NETWORK_DEVICE_LIST_TITLE),
969 STRING_TOKEN (STR_FORM_NETWORK_DEVICE_LIST_HELP),
970 EFI_IFR_FLAG_CALLBACK,
971 (EFI_QUESTION_ID) QUESTION_NETWORK_DEVICE_ID
972 );
973 }
974 } else if (mNextShowFormId == NETWORK_DEVICE_LIST_FORM_ID) {
975 //
976 // In network device list form, same mac address device only show one menu.
977 //
978 while (AddItemCount > 0) {
979 HiiCreateGotoOpCode (
980 StartOpCodeHandle,
981 INVALID_FORM_ID,
982 mMacDeviceList.NodeList[mMacDeviceList.CurListLen - AddItemCount].PromptId,
983 STRING_TOKEN (STR_NETWORK_DEVICE_HELP),
984 EFI_IFR_FLAG_CALLBACK,
985 mMacDeviceList.NodeList[mMacDeviceList.CurListLen - AddItemCount].QuestionId
986 );
987 AddItemCount -= 1;
988 }
989 } else if (mNextShowFormId == NETWORK_DEVICE_FORM_ID) {
990 //
991 // In network device form, only the selected mac address device need to be show.
992 //
993 HiiCreateGotoOpCode (
994 StartOpCodeHandle,
995 INVALID_FORM_ID,
996 Token,
997 TokenHelp,
998 EFI_IFR_FLAG_CALLBACK,
999 (EFI_QUESTION_ID) (Index + DEVICE_KEY_OFFSET)
1000 );
1001 }
1002 } else {
1003 //
1004 //
1005 // Not network device process, only need to show at device manger form.
1006 //
1007 if (mNextShowFormId == DEVICE_MANAGER_FORM_ID) {
1008 HiiCreateGotoOpCode (
1009 StartOpCodeHandle,
1010 INVALID_FORM_ID,
1011 Token,
1012 TokenHelp,
1013 EFI_IFR_FLAG_CALLBACK,
1014 (EFI_QUESTION_ID) (Index + DEVICE_KEY_OFFSET)
1015 );
1016 }
1017 }
1018
1019 //
1020 // Try to find more formset in this HiiHandle.
1021 //
1022 SkipCount++;
1023 Index--;
1024 }
1025
1026 Status = gBS->LocateHandleBuffer (
1027 ByProtocol,
1028 &gEfiDriverHealthProtocolGuid,
1029 NULL,
1030 &NumHandles,
1031 &DriverHealthHandles
1032 );
1033
1034 //
1035 // If there are no drivers installed driver health protocol, do not create driver health entry in UI
1036 //
1037 if (NumHandles != 0) {
1038 //
1039 // If driver health protocol is installed, create Driver Health subtitle and entry
1040 //
1041 HiiCreateSubTitleOpCode (StartOpCodeHandle, STRING_TOKEN (STR_DM_DRIVER_HEALTH_TITLE), 0, 0, 0);
1042 HiiCreateGotoOpCode (
1043 StartOpCodeHandle,
1044 DRIVER_HEALTH_FORM_ID,
1045 STRING_TOKEN(STR_DRIVER_HEALTH_ALL_HEALTHY), // Prompt text
1046 STRING_TOKEN(STR_DRIVER_HEALTH_STATUS_HELP), // Help text
1047 EFI_IFR_FLAG_CALLBACK,
1048 DEVICE_MANAGER_KEY_DRIVER_HEALTH // Question ID
1049 );
1050
1051 //
1052 // Check All Driver health status
1053 //
1054 if (!PlaformHealthStatusCheck ()) {
1055 //
1056 // At least one driver in the platform are not in healthy status
1057 //
1058 HiiSetString (HiiHandle, STRING_TOKEN (STR_DRIVER_HEALTH_ALL_HEALTHY), GetStringById (STRING_TOKEN (STR_DRIVER_NOT_HEALTH)), NULL);
1059 } else {
1060 //
1061 // For the string of STR_DRIVER_HEALTH_ALL_HEALTHY previously has been updated and we need to update it while re-entry.
1062 //
1063 HiiSetString (HiiHandle, STRING_TOKEN (STR_DRIVER_HEALTH_ALL_HEALTHY), GetStringById (STRING_TOKEN (STR_DRIVER_HEALTH_ALL_HEALTHY)), NULL);
1064 }
1065 }
1066
1067 HiiUpdateForm (
1068 HiiHandle,
1069 &gDeviceManagerFormSetGuid,
1070 mNextShowFormId,
1071 StartOpCodeHandle,
1072 EndOpCodeHandle
1073 );
1074
1075 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
1076 Status = gFormBrowser2->SendForm (
1077 gFormBrowser2,
1078 &HiiHandle,
1079 1,
1080 &gDeviceManagerFormSetGuid,
1081 mNextShowFormId,
1082 NULL,
1083 &ActionRequest
1084 );
1085 if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
1086 EnableResetRequired ();
1087 }
1088
1089 //
1090 // We will have returned from processing a callback, selected
1091 // a target to display
1092 //
1093 if ((gCallbackKey >= DEVICE_KEY_OFFSET)) {
1094 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
1095 Status = gFormBrowser2->SendForm (
1096 gFormBrowser2,
1097 &HiiHandles[gCallbackKey - DEVICE_KEY_OFFSET],
1098 1,
1099 GuidLists[gCallbackKey - DEVICE_KEY_OFFSET],
1100 0,
1101 NULL,
1102 &ActionRequest
1103 );
1104
1105 if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
1106 EnableResetRequired ();
1107 }
1108
1109 //
1110 // Force return to Device Manager
1111 //
1112 gCallbackKey = FRONT_PAGE_KEY_DEVICE_MANAGER;
1113 goto Done;
1114 }
1115
1116 //
1117 // Driver Health item chose.
1118 //
1119 if (gCallbackKey == DEVICE_MANAGER_KEY_DRIVER_HEALTH) {
1120 CallDriverHealth ();
1121 //
1122 // Force return to Device Manager
1123 //
1124 gCallbackKey = FRONT_PAGE_KEY_DEVICE_MANAGER;
1125 goto Done;
1126 }
1127
1128 //
1129 // Enter from device manager and into the network device list.
1130 //
1131 if (gCallbackKey == QUESTION_NETWORK_DEVICE_ID) {
1132 mNextShowFormId = NETWORK_DEVICE_LIST_FORM_ID;
1133 gCallbackKey = FRONT_PAGE_KEY_DEVICE_MANAGER;
1134 goto Done;
1135 }
1136
1137 //
1138 // In this case, go from the network device list to the specify device.
1139 //
1140 if ((gCallbackKey < MAX_KEY_SECTION_LEN + NETWORK_DEVICE_LIST_KEY_OFFSET ) && (gCallbackKey >= NETWORK_DEVICE_LIST_KEY_OFFSET)) {
1141 mNextShowFormId = NETWORK_DEVICE_FORM_ID;
1142 gCallbackKey = FRONT_PAGE_KEY_DEVICE_MANAGER;
1143 goto Done;
1144 }
1145
1146 //
1147 // Select the ESC, the gCallbackKey == 0.
1148 //
1149 if(mNextShowFormId - 1 < DEVICE_MANAGER_FORM_ID) {
1150 mNextShowFormId = DEVICE_MANAGER_FORM_ID;
1151 } else {
1152 mNextShowFormId = (UINT16) (mNextShowFormId - 1);
1153 gCallbackKey = FRONT_PAGE_KEY_DEVICE_MANAGER;
1154 }
1155
1156 Done:
1157 //
1158 // Remove our packagelist from HII database.
1159 //
1160 HiiRemovePackages (HiiHandle);
1161 gDeviceManagerPrivate.HiiHandle = NULL;
1162
1163 HiiFreeOpCodeHandle (StartOpCodeHandle);
1164 HiiFreeOpCodeHandle (EndOpCodeHandle);
1165 FreePool (HiiHandles);
1166
1167 for (Index = 0; Index < HandleNum; Index++) {
1168 if (GuidLists[Index] != NULL) {
1169 FreePool (GuidLists[Index]);
1170 }
1171 }
1172 FreePool (GuidLists);
1173
1174 return Status;
1175 }
1176
1177 /**
1178 This function is invoked if user selected a interactive opcode from Driver Health's
1179 Formset. The decision by user is saved to gCallbackKey for later processing.
1180
1181 @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
1182 @param Action Specifies the type of action taken by the browser.
1183 @param QuestionId A unique value which is sent to the original exporting driver
1184 so that it can identify the type of data to expect.
1185 @param Type The type of value for the question.
1186 @param Value A pointer to the data being sent to the original exporting driver.
1187 @param ActionRequest On return, points to the action requested by the callback function.
1188
1189 @retval EFI_SUCCESS The callback successfully handled the action.
1190 @retval EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
1191
1192 **/
1193 EFI_STATUS
1194 EFIAPI
1195 DriverHealthCallback (
1196 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
1197 IN EFI_BROWSER_ACTION Action,
1198 IN EFI_QUESTION_ID QuestionId,
1199 IN UINT8 Type,
1200 IN EFI_IFR_TYPE_VALUE *Value,
1201 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
1202 )
1203 {
1204 if (Action == EFI_BROWSER_ACTION_CHANGED) {
1205 if ((Value == NULL) || (ActionRequest == NULL)) {
1206 return EFI_INVALID_PARAMETER;
1207 }
1208
1209 gCallbackKey = QuestionId;
1210
1211 //
1212 // Request to exit SendForm(), so as to switch to selected form
1213 //
1214 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
1215
1216 return EFI_SUCCESS;
1217 }
1218
1219 //
1220 // All other action return unsupported.
1221 //
1222 return EFI_UNSUPPORTED;
1223 }
1224
1225 /**
1226 Collect and display the platform's driver health relative information, allow user to do interactive
1227 operation while the platform is unhealthy.
1228
1229 This function display a form which divided into two parts. The one list all modules which has installed
1230 driver health protocol. The list usually contain driver name, controller name, and it's health info.
1231 While the driver name can't be retrieved, will use device path as backup. The other part of the form provide
1232 a choice to the user to repair all platform.
1233
1234 **/
1235 VOID
1236 CallDriverHealth (
1237 VOID
1238 )
1239 {
1240 EFI_STATUS Status;
1241 EFI_HII_HANDLE HiiHandle;
1242 EFI_BROWSER_ACTION_REQUEST ActionRequest;
1243 EFI_IFR_GUID_LABEL *StartLabel;
1244 EFI_IFR_GUID_LABEL *StartLabelRepair;
1245 EFI_IFR_GUID_LABEL *EndLabel;
1246 EFI_IFR_GUID_LABEL *EndLabelRepair;
1247 VOID *StartOpCodeHandle;
1248 VOID *EndOpCodeHandle;
1249 VOID *StartOpCodeHandleRepair;
1250 VOID *EndOpCodeHandleRepair;
1251 UINTN Index;
1252 EFI_STRING_ID Token;
1253 EFI_STRING_ID TokenHelp;
1254 EFI_STRING String;
1255 EFI_STRING TmpString;
1256 EFI_STRING DriverName;
1257 EFI_STRING ControllerName;
1258 LIST_ENTRY DriverHealthList;
1259 DRIVER_HEALTH_INFO *DriverHealthInfo;
1260 LIST_ENTRY *Link;
1261 EFI_DEVICE_PATH_PROTOCOL *DriverDevicePath;
1262 BOOLEAN RebootRequired;
1263 UINTN StringSize;
1264
1265 Index = 0;
1266 DriverHealthInfo = NULL;
1267 DriverDevicePath = NULL;
1268 InitializeListHead (&DriverHealthList);
1269
1270 HiiHandle = gDeviceManagerPrivate.DriverHealthHiiHandle;
1271 if (HiiHandle == NULL) {
1272 //
1273 // Publish Driver Health HII data.
1274 //
1275 HiiHandle = HiiAddPackages (
1276 &gDeviceManagerFormSetGuid,
1277 gDeviceManagerPrivate.DriverHealthHandle,
1278 DriverHealthVfrBin,
1279 BdsDxeStrings,
1280 NULL
1281 );
1282 if (HiiHandle == NULL) {
1283 return;
1284 }
1285
1286 gDeviceManagerPrivate.DriverHealthHiiHandle = HiiHandle;
1287 }
1288
1289 //
1290 // Allocate space for creation of UpdateData Buffer
1291 //
1292 StartOpCodeHandle = HiiAllocateOpCodeHandle ();
1293 ASSERT (StartOpCodeHandle != NULL);
1294
1295 EndOpCodeHandle = HiiAllocateOpCodeHandle ();
1296 ASSERT (EndOpCodeHandle != NULL);
1297
1298 StartOpCodeHandleRepair = HiiAllocateOpCodeHandle ();
1299 ASSERT (StartOpCodeHandleRepair != NULL);
1300
1301 EndOpCodeHandleRepair = HiiAllocateOpCodeHandle ();
1302 ASSERT (EndOpCodeHandleRepair != NULL);
1303
1304 //
1305 // Create Hii Extend Label OpCode as the start opcode
1306 //
1307 StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
1308 StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1309 StartLabel->Number = LABEL_DRIVER_HEALTH;
1310
1311 //
1312 // Create Hii Extend Label OpCode as the start opcode
1313 //
1314 StartLabelRepair = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandleRepair, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
1315 StartLabelRepair->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1316 StartLabelRepair->Number = LABEL_DRIVER_HEALTH_REAPIR_ALL;
1317
1318 //
1319 // Create Hii Extend Label OpCode as the end opcode
1320 //
1321 EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
1322 EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1323 EndLabel->Number = LABEL_DRIVER_HEALTH_END;
1324
1325 //
1326 // Create Hii Extend Label OpCode as the end opcode
1327 //
1328 EndLabelRepair = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandleRepair, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
1329 EndLabelRepair->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1330 EndLabelRepair->Number = LABEL_DRIVER_HEALTH_REAPIR_ALL_END;
1331
1332 HiiCreateSubTitleOpCode (StartOpCodeHandle, STRING_TOKEN (STR_DH_STATUS_LIST), 0, 0, 1);
1333
1334 Status = GetAllControllersHealthStatus (&DriverHealthList);
1335 ASSERT (Status != EFI_OUT_OF_RESOURCES);
1336
1337 Link = GetFirstNode (&DriverHealthList);
1338
1339 while (!IsNull (&DriverHealthList, Link)) {
1340 DriverHealthInfo = DEVICE_MANAGER_HEALTH_INFO_FROM_LINK (Link);
1341
1342 //
1343 // Assume no line strings is longer than 512 bytes.
1344 //
1345 StringSize = 0x200;
1346 String = (EFI_STRING) AllocateZeroPool (StringSize);
1347 ASSERT (String != NULL);
1348
1349 Status = DriverHealthGetDriverName (DriverHealthInfo->DriverHandle, &DriverName);
1350 if (EFI_ERROR (Status)) {
1351 //
1352 // Can not get the Driver name, so use the Device path
1353 //
1354 DriverDevicePath = DevicePathFromHandle (DriverHealthInfo->DriverHandle);
1355 DriverName = DevicePathToStr (DriverDevicePath);
1356 }
1357 //
1358 // Add the Driver name & Controller name into FormSetTitle string
1359 //
1360 StrnCat (String, DriverName, StrLen (DriverName));
1361
1362
1363 Status = DriverHealthGetControllerName (
1364 DriverHealthInfo->DriverHandle,
1365 DriverHealthInfo->ControllerHandle,
1366 DriverHealthInfo->ChildHandle,
1367 &ControllerName
1368 );
1369
1370 if (!EFI_ERROR (Status)) {
1371 //
1372 // Can not get the Controller name, just let it empty.
1373 //
1374 StrnCat (String, L" ", StrLen (L" "));
1375 StrnCat (String, ControllerName, StrLen (ControllerName));
1376 }
1377
1378 //
1379 // Add the message of the Module itself provided after the string item.
1380 //
1381 if ((DriverHealthInfo->MessageList != NULL) && (DriverHealthInfo->MessageList->StringId != 0)) {
1382 StrnCat (String, L" ", StrLen (L" "));
1383 TmpString = HiiGetString (
1384 DriverHealthInfo->MessageList->HiiHandle,
1385 DriverHealthInfo->MessageList->StringId,
1386 NULL
1387 );
1388 } else {
1389 //
1390 // Update the string will be displayed base on the driver's health status
1391 //
1392 switch(DriverHealthInfo->HealthStatus) {
1393 case EfiDriverHealthStatusRepairRequired:
1394 TmpString = GetStringById (STRING_TOKEN (STR_REPAIR_REQUIRED));
1395 break;
1396 case EfiDriverHealthStatusConfigurationRequired:
1397 TmpString = GetStringById (STRING_TOKEN (STR_CONFIGURATION_REQUIRED));
1398 break;
1399 case EfiDriverHealthStatusFailed:
1400 TmpString = GetStringById (STRING_TOKEN (STR_OPERATION_FAILED));
1401 break;
1402 case EfiDriverHealthStatusReconnectRequired:
1403 TmpString = GetStringById (STRING_TOKEN (STR_RECONNECT_REQUIRED));
1404 break;
1405 case EfiDriverHealthStatusRebootRequired:
1406 TmpString = GetStringById (STRING_TOKEN (STR_REBOOT_REQUIRED));
1407 break;
1408 default:
1409 TmpString = GetStringById (STRING_TOKEN (STR_DRIVER_HEALTH_HEALTHY));
1410 break;
1411 }
1412 }
1413
1414 ASSERT (TmpString != NULL);
1415 StrnCat (String, TmpString, StringSize / sizeof (CHAR16) - StrLen (String) - 1);
1416 FreePool (TmpString);
1417
1418 Token = HiiSetString (HiiHandle, 0, String, NULL);
1419 FreePool (String);
1420
1421 TokenHelp = HiiSetString (HiiHandle, 0, GetStringById( STRING_TOKEN (STR_DH_REPAIR_SINGLE_HELP)), NULL);
1422
1423 HiiCreateActionOpCode (
1424 StartOpCodeHandle,
1425 (EFI_QUESTION_ID) (Index + DRIVER_HEALTH_KEY_OFFSET),
1426 Token,
1427 TokenHelp,
1428 EFI_IFR_FLAG_CALLBACK,
1429 0
1430 );
1431 Index++;
1432 Link = GetNextNode (&DriverHealthList, Link);
1433 }
1434
1435 //
1436 // Add End Opcode for Subtitle
1437 //
1438 HiiCreateEndOpCode (StartOpCodeHandle);
1439
1440 HiiCreateSubTitleOpCode (StartOpCodeHandleRepair, STRING_TOKEN (STR_DRIVER_HEALTH_REPAIR_ALL), 0, 0, 1);
1441 TokenHelp = HiiSetString (HiiHandle, 0, GetStringById( STRING_TOKEN (STR_DH_REPAIR_ALL_HELP)), NULL);
1442
1443 if (PlaformHealthStatusCheck ()) {
1444 //
1445 // No action need to do for the platform
1446 //
1447 Token = HiiSetString (HiiHandle, 0, GetStringById( STRING_TOKEN (STR_DRIVER_HEALTH_ALL_HEALTHY)), NULL);
1448 HiiCreateActionOpCode (
1449 StartOpCodeHandleRepair,
1450 0,
1451 Token,
1452 TokenHelp,
1453 EFI_IFR_FLAG_READ_ONLY,
1454 0
1455 );
1456 } else {
1457 //
1458 // Create ActionOpCode only while the platform need to do health related operation.
1459 //
1460 Token = HiiSetString (HiiHandle, 0, GetStringById( STRING_TOKEN (STR_DH_REPAIR_ALL_TITLE)), NULL);
1461 HiiCreateActionOpCode (
1462 StartOpCodeHandleRepair,
1463 (EFI_QUESTION_ID) DRIVER_HEALTH_REPAIR_ALL_KEY,
1464 Token,
1465 TokenHelp,
1466 EFI_IFR_FLAG_CALLBACK,
1467 0
1468 );
1469 }
1470
1471 HiiCreateEndOpCode (StartOpCodeHandleRepair);
1472
1473 Status = HiiUpdateForm (
1474 HiiHandle,
1475 &gDriverHealthFormSetGuid,
1476 DRIVER_HEALTH_FORM_ID,
1477 StartOpCodeHandle,
1478 EndOpCodeHandle
1479 );
1480 ASSERT (Status != EFI_NOT_FOUND);
1481 ASSERT (Status != EFI_BUFFER_TOO_SMALL);
1482
1483 Status = HiiUpdateForm (
1484 HiiHandle,
1485 &gDriverHealthFormSetGuid,
1486 DRIVER_HEALTH_FORM_ID,
1487 StartOpCodeHandleRepair,
1488 EndOpCodeHandleRepair
1489 );
1490 ASSERT (Status != EFI_NOT_FOUND);
1491 ASSERT (Status != EFI_BUFFER_TOO_SMALL);
1492
1493 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
1494 Status = gFormBrowser2->SendForm (
1495 gFormBrowser2,
1496 &HiiHandle,
1497 1,
1498 &gDriverHealthFormSetGuid,
1499 DRIVER_HEALTH_FORM_ID,
1500 NULL,
1501 &ActionRequest
1502 );
1503 if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
1504 EnableResetRequired ();
1505 }
1506
1507 //
1508 // We will have returned from processing a callback - user either hit ESC to exit, or selected
1509 // a target to display.
1510 // Process the diver health status states here.
1511 //
1512 if (gCallbackKey >= DRIVER_HEALTH_KEY_OFFSET && gCallbackKey != DRIVER_HEALTH_REPAIR_ALL_KEY) {
1513 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
1514
1515 Link = GetFirstNode (&DriverHealthList);
1516 Index = 0;
1517
1518 while (!IsNull (&DriverHealthList, Link)) {
1519 //
1520 // Got the item relative node in the List
1521 //
1522 if (Index == (gCallbackKey - DRIVER_HEALTH_KEY_OFFSET)) {
1523 DriverHealthInfo = DEVICE_MANAGER_HEALTH_INFO_FROM_LINK (Link);
1524 //
1525 // Process the driver's healthy status for the specify module
1526 //
1527 RebootRequired = FALSE;
1528 ProcessSingleControllerHealth (
1529 DriverHealthInfo->DriverHealth,
1530 DriverHealthInfo->ControllerHandle,
1531 DriverHealthInfo->ChildHandle,
1532 DriverHealthInfo->HealthStatus,
1533 &(DriverHealthInfo->MessageList),
1534 DriverHealthInfo->HiiHandle,
1535 &RebootRequired
1536 );
1537 if (RebootRequired) {
1538 gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
1539 }
1540 break;
1541 }
1542 Index++;
1543 Link = GetNextNode (&DriverHealthList, Link);
1544 }
1545
1546 if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
1547 EnableResetRequired ();
1548 }
1549
1550 //
1551 // Force return to the form of Driver Health in Device Manager
1552 //
1553 gCallbackKey = DRIVER_HEALTH_RETURN_KEY;
1554 }
1555
1556 //
1557 // Repair the whole platform
1558 //
1559 if (gCallbackKey == DRIVER_HEALTH_REPAIR_ALL_KEY) {
1560 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
1561
1562 PlatformRepairAll (&DriverHealthList);
1563
1564 gCallbackKey = DRIVER_HEALTH_RETURN_KEY;
1565 }
1566
1567 //
1568 // Remove driver health packagelist from HII database.
1569 //
1570 HiiRemovePackages (HiiHandle);
1571 gDeviceManagerPrivate.DriverHealthHiiHandle = NULL;
1572
1573 //
1574 // Free driver health info list
1575 //
1576 while (!IsListEmpty (&DriverHealthList)) {
1577
1578 Link = GetFirstNode(&DriverHealthList);
1579 DriverHealthInfo = DEVICE_MANAGER_HEALTH_INFO_FROM_LINK (Link);
1580 RemoveEntryList (Link);
1581
1582 if (DriverHealthInfo->MessageList != NULL) {
1583 FreePool(DriverHealthInfo->MessageList);
1584 FreePool (DriverHealthInfo);
1585 }
1586 }
1587
1588 HiiFreeOpCodeHandle (StartOpCodeHandle);
1589 HiiFreeOpCodeHandle (EndOpCodeHandle);
1590 HiiFreeOpCodeHandle (StartOpCodeHandleRepair);
1591 HiiFreeOpCodeHandle (EndOpCodeHandleRepair);
1592
1593 if (gCallbackKey == DRIVER_HEALTH_RETURN_KEY) {
1594 //
1595 // Force return to Driver Health Form
1596 //
1597 gCallbackKey = DEVICE_MANAGER_KEY_DRIVER_HEALTH;
1598 CallDriverHealth ();
1599 }
1600 }
1601
1602
1603 /**
1604 Check the Driver Health status of a single controller and try to process it if not healthy.
1605
1606 This function called by CheckAllControllersHealthStatus () function in order to process a specify
1607 contoller's health state.
1608
1609 @param DriverHealthList A Pointer to the list contain all of the platform driver health information.
1610 @param DriverHandle The handle of driver.
1611 @param ControllerHandle The class guid specifies which form set will be displayed.
1612 @param ChildHandle The handle of the child controller to retrieve the health
1613 status on. This is an optional parameter that may be NULL.
1614 @param DriverHealth A pointer to the EFI_DRIVER_HEALTH_PROTOCOL instance.
1615 @param HealthStatus The health status of the controller.
1616
1617 @retval EFI_INVALID_PARAMETER HealthStatus or DriverHealth is NULL.
1618 @retval HealthStatus The Health status of specify controller.
1619 @retval EFI_OUT_OF_RESOURCES The list of Driver Health Protocol handles can not be retrieved.
1620 @retval EFI_NOT_FOUND No controller in the platform install Driver Health Protocol.
1621 @retval EFI_SUCCESS The Health related operation has been taken successfully.
1622
1623 **/
1624 EFI_STATUS
1625 EFIAPI
1626 GetSingleControllerHealthStatus (
1627 IN OUT LIST_ENTRY *DriverHealthList,
1628 IN EFI_HANDLE DriverHandle,
1629 IN EFI_HANDLE ControllerHandle, OPTIONAL
1630 IN EFI_HANDLE ChildHandle, OPTIONAL
1631 IN EFI_DRIVER_HEALTH_PROTOCOL *DriverHealth,
1632 IN EFI_DRIVER_HEALTH_STATUS *HealthStatus
1633 )
1634 {
1635 EFI_STATUS Status;
1636 EFI_DRIVER_HEALTH_HII_MESSAGE *MessageList;
1637 EFI_HII_HANDLE FormHiiHandle;
1638 DRIVER_HEALTH_INFO *DriverHealthInfo;
1639
1640 if (HealthStatus == NULL) {
1641 //
1642 // If HealthStatus is NULL, then return EFI_INVALID_PARAMETER
1643 //
1644 return EFI_INVALID_PARAMETER;
1645 }
1646
1647 //
1648 // Assume the HealthStatus is healthy
1649 //
1650 *HealthStatus = EfiDriverHealthStatusHealthy;
1651
1652 if (DriverHealth == NULL) {
1653 //
1654 // If DriverHealth is NULL, then return EFI_INVALID_PARAMETER
1655 //
1656 return EFI_INVALID_PARAMETER;
1657 }
1658
1659 if (ControllerHandle == NULL) {
1660 //
1661 // If ControllerHandle is NULL, the return the cumulative health status of the driver
1662 //
1663 Status = DriverHealth->GetHealthStatus (DriverHealth, NULL, NULL, HealthStatus, NULL, NULL);
1664 if (*HealthStatus == EfiDriverHealthStatusHealthy) {
1665 //
1666 // Add the driver health related information into the list
1667 //
1668 DriverHealthInfo = AllocateZeroPool (sizeof (DRIVER_HEALTH_INFO));
1669 if (DriverHealthInfo == NULL) {
1670 return EFI_OUT_OF_RESOURCES;
1671 }
1672
1673 DriverHealthInfo->Signature = DEVICE_MANAGER_DRIVER_HEALTH_INFO_SIGNATURE;
1674 DriverHealthInfo->DriverHandle = DriverHandle;
1675 DriverHealthInfo->ControllerHandle = NULL;
1676 DriverHealthInfo->ChildHandle = NULL;
1677 DriverHealthInfo->HiiHandle = NULL;
1678 DriverHealthInfo->DriverHealth = DriverHealth;
1679 DriverHealthInfo->MessageList = NULL;
1680 DriverHealthInfo->HealthStatus = *HealthStatus;
1681
1682 InsertTailList (DriverHealthList, &DriverHealthInfo->Link);
1683 }
1684 return Status;
1685 }
1686
1687 MessageList = NULL;
1688 FormHiiHandle = NULL;
1689
1690 //
1691 // Collect the health status with the optional HII message list
1692 //
1693 Status = DriverHealth->GetHealthStatus (DriverHealth, ControllerHandle, ChildHandle, HealthStatus, &MessageList, &FormHiiHandle);
1694
1695 if (EFI_ERROR (Status)) {
1696 //
1697 // If the health status could not be retrieved, then return immediately
1698 //
1699 return Status;
1700 }
1701
1702 //
1703 // Add the driver health related information into the list
1704 //
1705 DriverHealthInfo = AllocateZeroPool (sizeof (DRIVER_HEALTH_INFO));
1706 if (DriverHealthInfo == NULL) {
1707 return EFI_OUT_OF_RESOURCES;
1708 }
1709
1710 DriverHealthInfo->Signature = DEVICE_MANAGER_DRIVER_HEALTH_INFO_SIGNATURE;
1711 DriverHealthInfo->DriverHandle = DriverHandle;
1712 DriverHealthInfo->ControllerHandle = ControllerHandle;
1713 DriverHealthInfo->ChildHandle = ChildHandle;
1714 DriverHealthInfo->HiiHandle = FormHiiHandle;
1715 DriverHealthInfo->DriverHealth = DriverHealth;
1716 DriverHealthInfo->MessageList = MessageList;
1717 DriverHealthInfo->HealthStatus = *HealthStatus;
1718
1719 InsertTailList (DriverHealthList, &DriverHealthInfo->Link);
1720
1721 return EFI_SUCCESS;
1722 }
1723
1724 /**
1725 Collects all the EFI Driver Health Protocols currently present in the EFI Handle Database,
1726 and queries each EFI Driver Health Protocol to determine if one or more of the controllers
1727 managed by each EFI Driver Health Protocol instance are not healthy.
1728
1729 @param DriverHealthList A Pointer to the list contain all of the platform driver health
1730 information.
1731
1732 @retval EFI_NOT_FOUND No controller in the platform install Driver Health Protocol.
1733 @retval EFI_SUCCESS All the controllers in the platform are healthy.
1734 @retval EFI_OUT_OF_RESOURCES The list of Driver Health Protocol handles can not be retrieved.
1735
1736 **/
1737 EFI_STATUS
1738 GetAllControllersHealthStatus (
1739 IN OUT LIST_ENTRY *DriverHealthList
1740 )
1741 {
1742 EFI_STATUS Status;
1743 UINTN NumHandles;
1744 EFI_HANDLE *DriverHealthHandles;
1745 EFI_DRIVER_HEALTH_PROTOCOL *DriverHealth;
1746 EFI_DRIVER_HEALTH_STATUS HealthStatus;
1747 UINTN DriverHealthIndex;
1748 EFI_HANDLE *Handles;
1749 UINTN HandleCount;
1750 UINTN ControllerIndex;
1751 UINTN ChildIndex;
1752
1753 //
1754 // Initialize local variables
1755 //
1756 Handles = NULL;
1757 DriverHealthHandles = NULL;
1758 NumHandles = 0;
1759 HandleCount = 0;
1760
1761 HealthStatus = EfiDriverHealthStatusHealthy;
1762
1763 Status = gBS->LocateHandleBuffer (
1764 ByProtocol,
1765 &gEfiDriverHealthProtocolGuid,
1766 NULL,
1767 &NumHandles,
1768 &DriverHealthHandles
1769 );
1770
1771 if (Status == EFI_NOT_FOUND || NumHandles == 0) {
1772 //
1773 // If there are no Driver Health Protocols handles, then return EFI_NOT_FOUND
1774 //
1775 return EFI_NOT_FOUND;
1776 }
1777
1778 if (EFI_ERROR (Status) || DriverHealthHandles == NULL) {
1779 //
1780 // If the list of Driver Health Protocol handles can not be retrieved, then
1781 // return EFI_OUT_OF_RESOURCES
1782 //
1783 return EFI_OUT_OF_RESOURCES;
1784 }
1785
1786 //
1787 // Check the health status of all controllers in the platform
1788 // Start by looping through all the Driver Health Protocol handles in the handle database
1789 //
1790 for (DriverHealthIndex = 0; DriverHealthIndex < NumHandles; DriverHealthIndex++) {
1791 //
1792 // Skip NULL Driver Health Protocol handles
1793 //
1794 if (DriverHealthHandles[DriverHealthIndex] == NULL) {
1795 continue;
1796 }
1797
1798 //
1799 // Retrieve the Driver Health Protocol from DriverHandle
1800 //
1801 Status = gBS->HandleProtocol (
1802 DriverHealthHandles[DriverHealthIndex],
1803 &gEfiDriverHealthProtocolGuid,
1804 (VOID **)&DriverHealth
1805 );
1806 if (EFI_ERROR (Status)) {
1807 //
1808 // If the Driver Health Protocol can not be retrieved, then skip to the next
1809 // Driver Health Protocol handle
1810 //
1811 continue;
1812 }
1813
1814 //
1815 // Check the health of all the controllers managed by a Driver Health Protocol handle
1816 //
1817 Status = GetSingleControllerHealthStatus (DriverHealthList, DriverHealthHandles[DriverHealthIndex], NULL, NULL, DriverHealth, &HealthStatus);
1818
1819 //
1820 // If Status is an error code, then the health information could not be retrieved, so assume healthy
1821 // and skip to the next Driver Health Protocol handle
1822 //
1823 if (EFI_ERROR (Status)) {
1824 continue;
1825 }
1826
1827 //
1828 // If all the controllers managed by this Driver Health Protocol are healthy, then skip to the next
1829 // Driver Health Protocol handle
1830 //
1831 if (HealthStatus == EfiDriverHealthStatusHealthy) {
1832 continue;
1833 }
1834
1835 //
1836 // See if the list of all handles in the handle database has been retrieved
1837 //
1838 //
1839 if (Handles == NULL) {
1840 //
1841 // Retrieve the list of all handles from the handle database
1842 //
1843 Status = gBS->LocateHandleBuffer (
1844 AllHandles,
1845 NULL,
1846 NULL,
1847 &HandleCount,
1848 &Handles
1849 );
1850 if (EFI_ERROR (Status) || Handles == NULL) {
1851 //
1852 // If all the handles in the handle database can not be retrieved, then
1853 // return EFI_OUT_OF_RESOURCES
1854 //
1855 Status = EFI_OUT_OF_RESOURCES;
1856 goto Done;
1857 }
1858 }
1859 //
1860 // Loop through all the controller handles in the handle database
1861 //
1862 for (ControllerIndex = 0; ControllerIndex < HandleCount; ControllerIndex++) {
1863 //
1864 // Skip NULL controller handles
1865 //
1866 if (Handles[ControllerIndex] == NULL) {
1867 continue;
1868 }
1869
1870 Status = GetSingleControllerHealthStatus (DriverHealthList, DriverHealthHandles[DriverHealthIndex], Handles[ControllerIndex], NULL, DriverHealth, &HealthStatus);
1871 if (EFI_ERROR (Status)) {
1872 //
1873 // If Status is an error code, then the health information could not be retrieved, so assume healthy
1874 //
1875 HealthStatus = EfiDriverHealthStatusHealthy;
1876 }
1877
1878 //
1879 // If CheckHealthSingleController() returned an error on a terminal state, then do not check the health of child controllers
1880 //
1881 if (EFI_ERROR (Status)) {
1882 continue;
1883 }
1884
1885 //
1886 // Loop through all the child handles in the handle database
1887 //
1888 for (ChildIndex = 0; ChildIndex < HandleCount; ChildIndex++) {
1889 //
1890 // Skip NULL child handles
1891 //
1892 if (Handles[ChildIndex] == NULL) {
1893 continue;
1894 }
1895
1896 Status = GetSingleControllerHealthStatus (DriverHealthList, DriverHealthHandles[DriverHealthIndex], Handles[ControllerIndex], Handles[ChildIndex], DriverHealth, &HealthStatus);
1897 if (EFI_ERROR (Status)) {
1898 //
1899 // If Status is an error code, then the health information could not be retrieved, so assume healthy
1900 //
1901 HealthStatus = EfiDriverHealthStatusHealthy;
1902 }
1903
1904 //
1905 // If CheckHealthSingleController() returned an error on a terminal state, then skip to the next child
1906 //
1907 if (EFI_ERROR (Status)) {
1908 continue;
1909 }
1910 }
1911 }
1912 }
1913
1914 Status = EFI_SUCCESS;
1915
1916 Done:
1917 if (Handles != NULL) {
1918 gBS->FreePool (Handles);
1919 }
1920 if (DriverHealthHandles != NULL) {
1921 gBS->FreePool (DriverHealthHandles);
1922 }
1923
1924 return Status;
1925 }
1926
1927
1928 /**
1929 Check the healthy status of the platform, this function will return immediately while found one driver
1930 in the platform are not healthy.
1931
1932 @retval FALSE at least one driver in the platform are not healthy.
1933 @retval TRUE No controller install Driver Health Protocol,
1934 or all controllers in the platform are in healthy status.
1935 **/
1936 BOOLEAN
1937 PlaformHealthStatusCheck (
1938 VOID
1939 )
1940 {
1941 EFI_DRIVER_HEALTH_STATUS HealthStatus;
1942 EFI_STATUS Status;
1943 UINTN Index;
1944 UINTN NoHandles;
1945 EFI_HANDLE *DriverHealthHandles;
1946 EFI_DRIVER_HEALTH_PROTOCOL *DriverHealth;
1947 BOOLEAN AllHealthy;
1948
1949 //
1950 // Initialize local variables
1951 //
1952 DriverHealthHandles = NULL;
1953 DriverHealth = NULL;
1954
1955 HealthStatus = EfiDriverHealthStatusHealthy;
1956
1957 Status = gBS->LocateHandleBuffer (
1958 ByProtocol,
1959 &gEfiDriverHealthProtocolGuid,
1960 NULL,
1961 &NoHandles,
1962 &DriverHealthHandles
1963 );
1964 //
1965 // There are no handles match the search for Driver Health Protocol has been installed.
1966 //
1967 if (Status == EFI_NOT_FOUND) {
1968 return TRUE;
1969 }
1970 //
1971 // Assume all modules are healthy.
1972 //
1973 AllHealthy = TRUE;
1974
1975 //
1976 // Found one or more Handles.
1977 //
1978 if (!EFI_ERROR (Status)) {
1979 for (Index = 0; Index < NoHandles; Index++) {
1980 Status = gBS->HandleProtocol (
1981 DriverHealthHandles[Index],
1982 &gEfiDriverHealthProtocolGuid,
1983 (VOID **) &DriverHealth
1984 );
1985 if (!EFI_ERROR (Status)) {
1986 Status = DriverHealth->GetHealthStatus (
1987 DriverHealth,
1988 NULL,
1989 NULL,
1990 &HealthStatus,
1991 NULL,
1992 NULL
1993 );
1994 }
1995 //
1996 // Get the healthy status of the module
1997 //
1998 if (!EFI_ERROR (Status)) {
1999 if (HealthStatus != EfiDriverHealthStatusHealthy) {
2000 //
2001 // Return immediately one driver's status not in healthy.
2002 //
2003 return FALSE;
2004 }
2005 }
2006 }
2007 }
2008 return AllHealthy;
2009 }
2010
2011 /**
2012 Processes a single controller using the EFI Driver Health Protocol associated with
2013 that controller. This algorithm continues to query the GetHealthStatus() service until
2014 one of the legal terminal states of the EFI Driver Health Protocol is reached. This may
2015 require the processing of HII Messages, HII Form, and invocation of repair operations.
2016
2017 @param DriverHealth A pointer to the EFI_DRIVER_HEALTH_PROTOCOL instance.
2018 @param ControllerHandle The class guid specifies which form set will be displayed.
2019 @param ChildHandle The handle of the child controller to retrieve the health
2020 status on. This is an optional parameter that may be NULL.
2021 @param HealthStatus The health status of the controller.
2022 @param MessageList An array of warning or error messages associated
2023 with the controller specified by ControllerHandle and
2024 ChildHandle. This is an optional parameter that may be NULL.
2025 @param FormHiiHandle The HII handle for an HII form associated with the
2026 controller specified by ControllerHandle and ChildHandle.
2027 @param RebootRequired Indicate whether a reboot is required to repair the controller.
2028 **/
2029 VOID
2030 ProcessSingleControllerHealth (
2031 IN EFI_DRIVER_HEALTH_PROTOCOL *DriverHealth,
2032 IN EFI_HANDLE ControllerHandle, OPTIONAL
2033 IN EFI_HANDLE ChildHandle, OPTIONAL
2034 IN EFI_DRIVER_HEALTH_STATUS HealthStatus,
2035 IN EFI_DRIVER_HEALTH_HII_MESSAGE **MessageList, OPTIONAL
2036 IN EFI_HII_HANDLE FormHiiHandle,
2037 IN OUT BOOLEAN *RebootRequired
2038 )
2039 {
2040 EFI_STATUS Status;
2041 EFI_DRIVER_HEALTH_STATUS LocalHealthStatus;
2042
2043 LocalHealthStatus = HealthStatus;
2044 //
2045 // If the module need to be repaired or reconfiguration, will process it until
2046 // reach a terminal status. The status from EfiDriverHealthStatusRepairRequired after repair
2047 // will be in (Health, Failed, Configuration Required).
2048 //
2049 while(LocalHealthStatus == EfiDriverHealthStatusConfigurationRequired ||
2050 LocalHealthStatus == EfiDriverHealthStatusRepairRequired) {
2051
2052 if (LocalHealthStatus == EfiDriverHealthStatusRepairRequired) {
2053 Status = DriverHealth->Repair (
2054 DriverHealth,
2055 ControllerHandle,
2056 ChildHandle,
2057 RepairNotify
2058 );
2059 }
2060 //
2061 // Via a form of the driver need to do configuration provided to process of status in
2062 // EfiDriverHealthStatusConfigurationRequired. The status after configuration should be in
2063 // (Healthy, Reboot Required, Failed, Reconnect Required, Repair Required).
2064 //
2065 if (LocalHealthStatus == EfiDriverHealthStatusConfigurationRequired) {
2066 if (FormHiiHandle != NULL) {
2067 Status = gFormBrowser2->SendForm (
2068 gFormBrowser2,
2069 &FormHiiHandle,
2070 1,
2071 &gEfiHiiDriverHealthFormsetGuid,
2072 0,
2073 NULL,
2074 NULL
2075 );
2076 ASSERT( !EFI_ERROR (Status));
2077 } else {
2078 //
2079 // Exit the loop in case no FormHiiHandle is supplied to prevent dead-loop
2080 //
2081 break;
2082 }
2083 }
2084
2085 Status = DriverHealth->GetHealthStatus (
2086 DriverHealth,
2087 ControllerHandle,
2088 ChildHandle,
2089 &LocalHealthStatus,
2090 NULL,
2091 &FormHiiHandle
2092 );
2093 ASSERT_EFI_ERROR (Status);
2094
2095 if (*MessageList != NULL) {
2096 ProcessMessages (*MessageList);
2097 }
2098 }
2099
2100 //
2101 // Health status in {Healthy, Failed} may also have Messages need to process
2102 //
2103 if (LocalHealthStatus == EfiDriverHealthStatusHealthy || LocalHealthStatus == EfiDriverHealthStatusFailed) {
2104 if (*MessageList != NULL) {
2105 ProcessMessages (*MessageList);
2106 }
2107 }
2108 //
2109 // Check for RebootRequired or ReconnectRequired
2110 //
2111 if (LocalHealthStatus == EfiDriverHealthStatusRebootRequired) {
2112 *RebootRequired = TRUE;
2113 }
2114
2115 //
2116 // Do reconnect if need.
2117 //
2118 if (LocalHealthStatus == EfiDriverHealthStatusReconnectRequired) {
2119 Status = gBS->DisconnectController (ControllerHandle, NULL, NULL);
2120 if (EFI_ERROR (Status)) {
2121 //
2122 // Disconnect failed. Need to promote reconnect to a reboot.
2123 //
2124 *RebootRequired = TRUE;
2125 } else {
2126 gBS->ConnectController (ControllerHandle, NULL, NULL, TRUE);
2127 }
2128 }
2129 }
2130
2131
2132 /**
2133 Reports the progress of a repair operation.
2134
2135 @param[in] Value A value between 0 and Limit that identifies the current
2136 progress of the repair operation.
2137
2138 @param[in] Limit The maximum value of Value for the current repair operation.
2139 For example, a driver that wants to specify progress in
2140 percent would use a Limit value of 100.
2141
2142 @retval EFI_SUCCESS The progress of a repair operation is reported successfully.
2143
2144 **/
2145 EFI_STATUS
2146 EFIAPI
2147 RepairNotify (
2148 IN UINTN Value,
2149 IN UINTN Limit
2150 )
2151 {
2152 UINTN Percent;
2153
2154 if (Limit == 0) {
2155 Print(L"Repair Progress Undefined\n\r");
2156 } else {
2157 Percent = Value * 100 / Limit;
2158 Print(L"Repair Progress = %3d%%\n\r", Percent);
2159 }
2160 return EFI_SUCCESS;
2161 }
2162
2163 /**
2164 Processes a set of messages returned by the GetHealthStatus ()
2165 service of the EFI Driver Health Protocol
2166
2167 @param MessageList The MessageList point to messages need to processed.
2168
2169 **/
2170 VOID
2171 ProcessMessages (
2172 IN EFI_DRIVER_HEALTH_HII_MESSAGE *MessageList
2173 )
2174 {
2175 UINTN MessageIndex;
2176 EFI_STRING MessageString;
2177
2178 for (MessageIndex = 0;
2179 MessageList[MessageIndex].HiiHandle != NULL;
2180 MessageIndex++) {
2181
2182 MessageString = HiiGetString (
2183 MessageList[MessageIndex].HiiHandle,
2184 MessageList[MessageIndex].StringId,
2185 NULL
2186 );
2187 if (MessageString != NULL) {
2188 //
2189 // User can customize the output. Just simply print out the MessageString like below.
2190 // Also can use the HiiHandle to display message on the front page.
2191 //
2192 // Print(L"%s\n",MessageString);
2193 // gBS->Stall (100000);
2194 }
2195 }
2196
2197 }
2198
2199 /**
2200 Repair the whole platform.
2201
2202 This function is the main entry for user choose "Repair All" in the front page.
2203 It will try to do recovery job till all the driver health protocol installed modules
2204 reach a terminal state.
2205
2206 @param DriverHealthList A Pointer to the list contain all of the platform driver health
2207 information.
2208
2209 **/
2210 VOID
2211 PlatformRepairAll (
2212 IN LIST_ENTRY *DriverHealthList
2213 )
2214 {
2215 DRIVER_HEALTH_INFO *DriverHealthInfo;
2216 LIST_ENTRY *Link;
2217 BOOLEAN RebootRequired;
2218
2219 ASSERT (DriverHealthList != NULL);
2220
2221 RebootRequired = FALSE;
2222
2223 for ( Link = GetFirstNode (DriverHealthList)
2224 ; !IsNull (DriverHealthList, Link)
2225 ; Link = GetNextNode (DriverHealthList, Link)
2226 ) {
2227 DriverHealthInfo = DEVICE_MANAGER_HEALTH_INFO_FROM_LINK (Link);
2228 //
2229 // Do driver health status operation by each link node
2230 //
2231 ASSERT (DriverHealthInfo != NULL);
2232
2233 ProcessSingleControllerHealth (
2234 DriverHealthInfo->DriverHealth,
2235 DriverHealthInfo->ControllerHandle,
2236 DriverHealthInfo->ChildHandle,
2237 DriverHealthInfo->HealthStatus,
2238 &(DriverHealthInfo->MessageList),
2239 DriverHealthInfo->HiiHandle,
2240 &RebootRequired
2241 );
2242 }
2243
2244 if (RebootRequired) {
2245 gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
2246 }
2247 }
2248
2249 /**
2250
2251 Select the best matching language according to front page policy for best user experience.
2252
2253 This function supports both ISO 639-2 and RFC 4646 language codes, but language
2254 code types may not be mixed in a single call to this function.
2255
2256 @param SupportedLanguages A pointer to a Null-terminated ASCII string that
2257 contains a set of language codes in the format
2258 specified by Iso639Language.
2259 @param Iso639Language If TRUE, then all language codes are assumed to be
2260 in ISO 639-2 format. If FALSE, then all language
2261 codes are assumed to be in RFC 4646 language format.
2262
2263 @retval NULL The best matching language could not be found in SupportedLanguages.
2264 @retval NULL There are not enough resources available to return the best matching
2265 language.
2266 @retval Other A pointer to a Null-terminated ASCII string that is the best matching
2267 language in SupportedLanguages.
2268 **/
2269 CHAR8 *
2270 DriverHealthSelectBestLanguage (
2271 IN CHAR8 *SupportedLanguages,
2272 IN BOOLEAN Iso639Language
2273 )
2274 {
2275 CHAR8 *LanguageVariable;
2276 CHAR8 *BestLanguage;
2277
2278 GetEfiGlobalVariable2 (Iso639Language ? L"Lang" : L"PlatformLang", (VOID**)&LanguageVariable, NULL);
2279
2280 BestLanguage = GetBestLanguage(
2281 SupportedLanguages,
2282 Iso639Language,
2283 (LanguageVariable != NULL) ? LanguageVariable : "",
2284 Iso639Language ? "eng" : "en-US",
2285 NULL
2286 );
2287 if (LanguageVariable != NULL) {
2288 FreePool (LanguageVariable);
2289 }
2290
2291 return BestLanguage;
2292 }
2293
2294
2295
2296 /**
2297
2298 This is an internal worker function to get the Component Name (2) protocol interface
2299 and the language it supports.
2300
2301 @param ProtocolGuid A pointer to an EFI_GUID. It points to Component Name (2) protocol GUID.
2302 @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved.
2303 @param ComponentName A pointer to the Component Name (2) protocol interface.
2304 @param SupportedLanguage The best suitable language that matches the SupportedLangues interface for the
2305 located Component Name (2) instance.
2306
2307 @retval EFI_SUCCESS The Component Name (2) protocol instance is successfully located and we find
2308 the best matching language it support.
2309 @retval EFI_UNSUPPORTED The input Language is not supported by the Component Name (2) protocol.
2310 @retval Other Some error occurs when locating Component Name (2) protocol instance or finding
2311 the supported language.
2312
2313 **/
2314 EFI_STATUS
2315 GetComponentNameWorker (
2316 IN EFI_GUID *ProtocolGuid,
2317 IN EFI_HANDLE DriverBindingHandle,
2318 OUT EFI_COMPONENT_NAME_PROTOCOL **ComponentName,
2319 OUT CHAR8 **SupportedLanguage
2320 )
2321 {
2322 EFI_STATUS Status;
2323
2324 //
2325 // Locate Component Name (2) protocol on the driver binging handle.
2326 //
2327 Status = gBS->OpenProtocol (
2328 DriverBindingHandle,
2329 ProtocolGuid,
2330 (VOID **) ComponentName,
2331 NULL,
2332 NULL,
2333 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2334 );
2335 if (EFI_ERROR (Status)) {
2336 return Status;
2337 }
2338
2339 //
2340 // Apply shell policy to select the best language.
2341 //
2342 *SupportedLanguage = DriverHealthSelectBestLanguage (
2343 (*ComponentName)->SupportedLanguages,
2344 (BOOLEAN) (ProtocolGuid == &gEfiComponentNameProtocolGuid)
2345 );
2346 if (*SupportedLanguage == NULL) {
2347 Status = EFI_UNSUPPORTED;
2348 }
2349
2350 return Status;
2351 }
2352
2353 /**
2354
2355 This is an internal worker function to get driver name from Component Name (2) protocol interface.
2356
2357
2358 @param ProtocolGuid A pointer to an EFI_GUID. It points to Component Name (2) protocol GUID.
2359 @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved.
2360 @param DriverName A pointer to the Unicode string to return. This Unicode string is the name
2361 of the driver specified by This.
2362
2363 @retval EFI_SUCCESS The driver name is successfully retrieved from Component Name (2) protocol
2364 interface.
2365 @retval Other The driver name cannot be retrieved from Component Name (2) protocol
2366 interface.
2367
2368 **/
2369 EFI_STATUS
2370 GetDriverNameWorker (
2371 IN EFI_GUID *ProtocolGuid,
2372 IN EFI_HANDLE DriverBindingHandle,
2373 OUT CHAR16 **DriverName
2374 )
2375 {
2376 EFI_STATUS Status;
2377 CHAR8 *BestLanguage;
2378 EFI_COMPONENT_NAME_PROTOCOL *ComponentName;
2379
2380 //
2381 // Retrieve Component Name (2) protocol instance on the driver binding handle and
2382 // find the best language this instance supports.
2383 //
2384 Status = GetComponentNameWorker (
2385 ProtocolGuid,
2386 DriverBindingHandle,
2387 &ComponentName,
2388 &BestLanguage
2389 );
2390 if (EFI_ERROR (Status)) {
2391 return Status;
2392 }
2393
2394 //
2395 // Get the driver name from Component Name (2) protocol instance on the driver binging handle.
2396 //
2397 Status = ComponentName->GetDriverName (
2398 ComponentName,
2399 BestLanguage,
2400 DriverName
2401 );
2402 FreePool (BestLanguage);
2403
2404 return Status;
2405 }
2406
2407 /**
2408
2409 This function gets driver name from Component Name 2 protocol interface and Component Name protocol interface
2410 in turn. It first tries UEFI 2.0 Component Name 2 protocol interface and try to get the driver name.
2411 If the attempt fails, it then gets the driver name from EFI 1.1 Component Name protocol for backward
2412 compatibility support.
2413
2414 @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved.
2415 @param DriverName A pointer to the Unicode string to return. This Unicode string is the name
2416 of the driver specified by This.
2417
2418 @retval EFI_SUCCESS The driver name is successfully retrieved from Component Name (2) protocol
2419 interface.
2420 @retval Other The driver name cannot be retrieved from Component Name (2) protocol
2421 interface.
2422
2423 **/
2424 EFI_STATUS
2425 DriverHealthGetDriverName (
2426 IN EFI_HANDLE DriverBindingHandle,
2427 OUT CHAR16 **DriverName
2428 )
2429 {
2430 EFI_STATUS Status;
2431
2432 //
2433 // Get driver name from UEFI 2.0 Component Name 2 protocol interface.
2434 //
2435 Status = GetDriverNameWorker (&gEfiComponentName2ProtocolGuid, DriverBindingHandle, DriverName);
2436 if (EFI_ERROR (Status)) {
2437 //
2438 // If it fails to get the driver name from Component Name protocol interface, we should fall back on
2439 // EFI 1.1 Component Name protocol interface.
2440 //
2441 Status = GetDriverNameWorker (&gEfiComponentNameProtocolGuid, DriverBindingHandle, DriverName);
2442 }
2443
2444 return Status;
2445 }
2446
2447
2448
2449 /**
2450 This function gets controller name from Component Name 2 protocol interface and Component Name protocol interface
2451 in turn. It first tries UEFI 2.0 Component Name 2 protocol interface and try to get the controller name.
2452 If the attempt fails, it then gets the controller name from EFI 1.1 Component Name protocol for backward
2453 compatibility support.
2454
2455 @param ProtocolGuid A pointer to an EFI_GUID. It points to Component Name (2) protocol GUID.
2456 @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved.
2457 @param ControllerHandle The handle of a controller that the driver specified by This is managing.
2458 This handle specifies the controller whose name is to be returned.
2459 @param ChildHandle The handle of the child controller to retrieve the name of. This is an
2460 optional parameter that may be NULL. It will be NULL for device drivers.
2461 It will also be NULL for bus drivers that attempt to retrieve the name
2462 of the bus controller. It will not be NULL for a bus driver that attempts
2463 to retrieve the name of a child controller.
2464 @param ControllerName A pointer to the Unicode string to return. This Unicode string
2465 is the name of the controller specified by ControllerHandle and ChildHandle.
2466
2467 @retval EFI_SUCCESS The controller name is successfully retrieved from Component Name (2) protocol
2468 interface.
2469 @retval Other The controller name cannot be retrieved from Component Name (2) protocol.
2470
2471 **/
2472 EFI_STATUS
2473 GetControllerNameWorker (
2474 IN EFI_GUID *ProtocolGuid,
2475 IN EFI_HANDLE DriverBindingHandle,
2476 IN EFI_HANDLE ControllerHandle,
2477 IN EFI_HANDLE ChildHandle,
2478 OUT CHAR16 **ControllerName
2479 )
2480 {
2481 EFI_STATUS Status;
2482 CHAR8 *BestLanguage;
2483 EFI_COMPONENT_NAME_PROTOCOL *ComponentName;
2484
2485 //
2486 // Retrieve Component Name (2) protocol instance on the driver binding handle and
2487 // find the best language this instance supports.
2488 //
2489 Status = GetComponentNameWorker (
2490 ProtocolGuid,
2491 DriverBindingHandle,
2492 &ComponentName,
2493 &BestLanguage
2494 );
2495 if (EFI_ERROR (Status)) {
2496 return Status;
2497 }
2498
2499 //
2500 // Get the controller name from Component Name (2) protocol instance on the driver binging handle.
2501 //
2502 Status = ComponentName->GetControllerName (
2503 ComponentName,
2504 ControllerHandle,
2505 ChildHandle,
2506 BestLanguage,
2507 ControllerName
2508 );
2509 FreePool (BestLanguage);
2510
2511 return Status;
2512 }
2513
2514 /**
2515
2516 This function gets controller name from Component Name 2 protocol interface and Component Name protocol interface
2517 in turn. It first tries UEFI 2.0 Component Name 2 protocol interface and try to get the controller name.
2518 If the attempt fails, it then gets the controller name from EFI 1.1 Component Name protocol for backward
2519 compatibility support.
2520
2521 @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved.
2522 @param ControllerHandle The handle of a controller that the driver specified by This is managing.
2523 This handle specifies the controller whose name is to be returned.
2524 @param ChildHandle The handle of the child controller to retrieve the name of. This is an
2525 optional parameter that may be NULL. It will be NULL for device drivers.
2526 It will also be NULL for bus drivers that attempt to retrieve the name
2527 of the bus controller. It will not be NULL for a bus driver that attempts
2528 to retrieve the name of a child controller.
2529 @param ControllerName A pointer to the Unicode string to return. This Unicode string
2530 is the name of the controller specified by ControllerHandle and ChildHandle.
2531
2532 @retval EFI_SUCCESS The controller name is successfully retrieved from Component Name (2) protocol
2533 interface.
2534 @retval Other The controller name cannot be retrieved from Component Name (2) protocol.
2535
2536 **/
2537 EFI_STATUS
2538 DriverHealthGetControllerName (
2539 IN EFI_HANDLE DriverBindingHandle,
2540 IN EFI_HANDLE ControllerHandle,
2541 IN EFI_HANDLE ChildHandle,
2542 OUT CHAR16 **ControllerName
2543 )
2544 {
2545 EFI_STATUS Status;
2546
2547 //
2548 // Get controller name from UEFI 2.0 Component Name 2 protocol interface.
2549 //
2550 Status = GetControllerNameWorker (
2551 &gEfiComponentName2ProtocolGuid,
2552 DriverBindingHandle,
2553 ControllerHandle,
2554 ChildHandle,
2555 ControllerName
2556 );
2557 if (EFI_ERROR (Status)) {
2558 //
2559 // If it fails to get the controller name from Component Name protocol interface, we should fall back on
2560 // EFI 1.1 Component Name protocol interface.
2561 //
2562 Status = GetControllerNameWorker (
2563 &gEfiComponentNameProtocolGuid,
2564 DriverBindingHandle,
2565 ControllerHandle,
2566 ChildHandle,
2567 ControllerName
2568 );
2569 }
2570
2571 return Status;
2572 }