1 /** @file
2 The device manager reference implementation
3 
4 Copyright (c) 2004 - 2015, 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   {
22     DeviceManagerExtractConfig,
23     DeviceManagerRouteConfig,
24     DeviceManagerCallback
25   }
26 };
27 
28 #define  MAX_MAC_ADDRESS_NODE_LIST_LEN    10
29 
30 EFI_GUID mDeviceManagerGuid = DEVICE_MANAGER_FORMSET_GUID;
31 
32 //
33 // Which Mac Address string is select
34 // it will decide what menu need to show in the NETWORK_DEVICE_FORM_ID form.
35 //
36 EFI_STRING  mSelectedMacAddrString;
37 
38 //
39 // The Mac Address show in the NETWORK_DEVICE_LIST_FORM_ID
40 //
41 MAC_ADDRESS_NODE_LIST  mMacDeviceList;
42 
43 HII_VENDOR_DEVICE_PATH  mDeviceManagerHiiVendorDevicePath = {
44   {
45     {
46       HARDWARE_DEVICE_PATH,
47       HW_VENDOR_DP,
48       {
49         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
50         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
51       }
52     },
53     //
54     // {102579A0-3686-466e-ACD8-80C087044F4A}
55     //
56     { 0x102579a0, 0x3686, 0x466e, { 0xac, 0xd8, 0x80, 0xc0, 0x87, 0x4, 0x4f, 0x4a } }
57   },
58   {
59     END_DEVICE_PATH_TYPE,
60     END_ENTIRE_DEVICE_PATH_SUBTYPE,
61     {
62       (UINT8) (END_DEVICE_PATH_LENGTH),
63       (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
64     }
65   }
66 };
67 
68 /**
69   Extract device path for given HII handle and class guid.
70 
71   @param Handle          The HII handle.
72 
73   @retval  NULL          Fail to get the device path string.
74   @return  PathString    Get the device path string.
75 
76 **/
77 CHAR16 *
DmExtractDevicePathFromHiiHandle(IN EFI_HII_HANDLE Handle)78 DmExtractDevicePathFromHiiHandle (
79   IN      EFI_HII_HANDLE      Handle
80   )
81 {
82   EFI_STATUS                       Status;
83   EFI_HANDLE                       DriverHandle;
84 
85   ASSERT (Handle != NULL);
86 
87   if (Handle == NULL) {
88     return NULL;
89   }
90 
91   Status = gHiiDatabase->GetPackageListHandle (gHiiDatabase, Handle, &DriverHandle);
92   if (EFI_ERROR (Status)) {
93     return NULL;
94   }
95   //
96   // Get device path string.
97   //
98   return ConvertDevicePathToText(DevicePathFromHandle (DriverHandle), FALSE, FALSE);
99 }
100 
101 /**
102   Get the mac address string from the device path.
103   if the device path has the vlan, get the vanid also.
104 
105   @param MacAddressNode              Device path begin with mac address
106   @param PBuffer                     Output string buffer contain mac address.
107 
108 **/
109 BOOLEAN
GetMacAddressString(IN MAC_ADDR_DEVICE_PATH * MacAddressNode,OUT CHAR16 ** PBuffer)110 GetMacAddressString(
111   IN  MAC_ADDR_DEVICE_PATH   *MacAddressNode,
112   OUT CHAR16                 **PBuffer
113   )
114 {
115   UINTN                 HwAddressSize;
116   UINTN                 Index;
117   UINT8                 *HwAddress;
118   EFI_DEVICE_PATH_PROTOCOL  *Node;
119   UINT16                VlanId;
120   CHAR16                *String;
121   UINTN                 BufferLen;
122 
123   VlanId = 0;
124   String = NULL;
125   ASSERT(MacAddressNode != NULL);
126 
127   HwAddressSize = sizeof (EFI_MAC_ADDRESS);
128   if (MacAddressNode->IfType == 0x01 || MacAddressNode->IfType == 0x00) {
129     HwAddressSize = 6;
130   }
131 
132   //
133   // The output format is MAC:XX:XX:XX:...\XXXX
134   // The size is the Number size + ":" size + Vlan size(\XXXX) + End
135   //
136   BufferLen = (4 + 2 * HwAddressSize + (HwAddressSize - 1) + 5 + 1) * sizeof (CHAR16);
137   String = AllocateZeroPool (BufferLen);
138   if (String == NULL) {
139     return FALSE;
140   }
141 
142   *PBuffer = String;
143   StrCpyS(String, BufferLen / sizeof (CHAR16), L"MAC:");
144   String += 4;
145 
146   //
147   // Convert the MAC address into a unicode string.
148   //
149   HwAddress = &MacAddressNode->MacAddress.Addr[0];
150   for (Index = 0; Index < HwAddressSize; Index++) {
151     String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(HwAddress++), 2);
152     if (Index < HwAddressSize - 1) {
153       *String++ = L':';
154     }
155   }
156 
157   //
158   // If VLAN is configured, it will need extra 5 characters like "\0005".
159   // Plus one unicode character for the null-terminator.
160   //
161   Node = (EFI_DEVICE_PATH_PROTOCOL  *)MacAddressNode;
162   while (!IsDevicePathEnd (Node)) {
163     if (Node->Type == MESSAGING_DEVICE_PATH && Node->SubType == MSG_VLAN_DP) {
164       VlanId = ((VLAN_DEVICE_PATH *) Node)->VlanId;
165     }
166     Node = NextDevicePathNode (Node);
167   }
168 
169   if (VlanId != 0) {
170     *String++ = L'\\';
171     String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, VlanId, 4);
172   }
173 
174   //
175   // Null terminate the Unicode string
176   //
177   *String = L'\0';
178 
179   return TRUE;
180 }
181 
182 /**
183   Save question id and prompt id to the mac device list.
184   If the same mac address has saved yet, no need to add more.
185 
186   @param MacAddrString               Mac address string.
187 
188   @retval  EFI_SUCCESS               Add the item is successful.
189   @return  Other values if failed to Add the item.
190 **/
191 BOOLEAN
AddIdToMacDeviceList(IN EFI_STRING MacAddrString)192 AddIdToMacDeviceList (
193   IN  EFI_STRING        MacAddrString
194   )
195 {
196   MENU_INFO_ITEM *TempDeviceList;
197   UINTN          Index;
198   EFI_STRING     StoredString;
199   EFI_STRING_ID  PromptId;
200   EFI_HII_HANDLE HiiHandle;
201 
202   HiiHandle =   gDeviceManagerPrivate.HiiHandle;
203   TempDeviceList = NULL;
204 
205   for (Index = 0; Index < mMacDeviceList.CurListLen; Index ++) {
206     StoredString = HiiGetString (HiiHandle, mMacDeviceList.NodeList[Index].PromptId, NULL);
207     if (StoredString == NULL) {
208       return FALSE;
209     }
210 
211     //
212     // Already has save the same mac address to the list.
213     //
214     if (StrCmp (MacAddrString, StoredString) == 0) {
215       return FALSE;
216     }
217   }
218 
219   PromptId = HiiSetString(HiiHandle, 0, MacAddrString, NULL);
220   //
221   // If not in the list, save it.
222   //
223   if (mMacDeviceList.MaxListLen > mMacDeviceList.CurListLen + 1) {
224     mMacDeviceList.NodeList[mMacDeviceList.CurListLen].PromptId = PromptId;
225     mMacDeviceList.NodeList[mMacDeviceList.CurListLen].QuestionId = (EFI_QUESTION_ID) (mMacDeviceList.CurListLen + NETWORK_DEVICE_LIST_KEY_OFFSET);
226   } else {
227     mMacDeviceList.MaxListLen += MAX_MAC_ADDRESS_NODE_LIST_LEN;
228     if (mMacDeviceList.CurListLen != 0) {
229       TempDeviceList = (MENU_INFO_ITEM *)AllocateCopyPool (sizeof (MENU_INFO_ITEM) * mMacDeviceList.MaxListLen, (VOID *)mMacDeviceList.NodeList);
230     } else {
231       TempDeviceList = (MENU_INFO_ITEM *)AllocatePool (sizeof (MENU_INFO_ITEM) * mMacDeviceList.MaxListLen);
232     }
233 
234     if (TempDeviceList == NULL) {
235       return FALSE;
236     }
237     TempDeviceList[mMacDeviceList.CurListLen].PromptId = PromptId;
238     TempDeviceList[mMacDeviceList.CurListLen].QuestionId = (EFI_QUESTION_ID) (mMacDeviceList.CurListLen + NETWORK_DEVICE_LIST_KEY_OFFSET);
239 
240     if (mMacDeviceList.CurListLen > 0) {
241       FreePool(mMacDeviceList.NodeList);
242     }
243 
244     mMacDeviceList.NodeList = TempDeviceList;
245   }
246   mMacDeviceList.CurListLen ++;
247 
248   return TRUE;
249 }
250 
251 /**
252   Check the devcie path, try to find whether it has mac address path.
253 
254   In this function, first need to check whether this path has mac address path.
255   second, when the mac address device path has find, also need to deicide whether
256   need to add this mac address relate info to the menu.
257 
258   @param    *Node            Input device which need to be check.
259   @param    NextShowFormId   FormId Which need to be show.
260   @param    *NeedAddItem     Whether need to add the menu in the network device list.
261 
262   @retval  TRUE              Has mac address device path.
263   @retval  FALSE             NOT Has mac address device path.
264 
265 **/
266 BOOLEAN
IsMacAddressDevicePath(IN VOID * Node,IN EFI_FORM_ID NextShowFormId,OUT BOOLEAN * NeedAddItem)267 IsMacAddressDevicePath (
268   IN  VOID          *Node,
269   IN EFI_FORM_ID    NextShowFormId,
270   OUT BOOLEAN       *NeedAddItem
271   )
272 {
273   EFI_DEVICE_PATH_PROTOCOL   *DevicePath;
274   CHAR16                     *Buffer;
275   BOOLEAN                    ReturnVal;
276 
277   ASSERT (Node != NULL);
278   *NeedAddItem = FALSE;
279   ReturnVal    = FALSE;
280   Buffer    = NULL;
281 
282   DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Node;
283 
284   //
285   // find the partition device path node
286   //
287   while (!IsDevicePathEnd (DevicePath)) {
288     if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
289        (DevicePathSubType (DevicePath) == MSG_MAC_ADDR_DP)) {
290       ReturnVal = TRUE;
291 
292       if (DEVICE_MANAGER_FORM_ID == NextShowFormId) {
293         *NeedAddItem = TRUE;
294         break;
295       }
296 
297       if (!GetMacAddressString((MAC_ADDR_DEVICE_PATH*)DevicePath, &Buffer)) {
298         break;
299       }
300 
301       if (NETWORK_DEVICE_FORM_ID == NextShowFormId) {
302         if (StrCmp (Buffer, mSelectedMacAddrString) == 0) {
303           *NeedAddItem = TRUE;
304         }
305         break;
306       }
307 
308       if (NETWORK_DEVICE_LIST_FORM_ID == NextShowFormId) {
309         //
310         // Same handle may has two network child handle, so the questionid
311         // has the offset of SAME_HANDLE_KEY_OFFSET.
312         //
313         if (AddIdToMacDeviceList (Buffer)) {
314           *NeedAddItem = TRUE;
315         }
316         break;
317       }
318     }
319     DevicePath = NextDevicePathNode (DevicePath);
320   }
321 
322   if (Buffer != NULL) {
323     FreePool (Buffer);
324   }
325 
326   return ReturnVal;
327 }
328 
329 /**
330   Check to see if the device path is for the network device.
331 
332   @param Handle          The HII handle which include the mac address device path.
333   @param NextShowFormId  The FormId of the form which will be show next time.
334   @param ItemCount       The new add Mac address item count.
335 
336   @retval  TRUE          Need to add new item in the menu.
337   @return  FALSE         Do not need to add the menu about the network.
338 
339 **/
340 BOOLEAN
IsNeedAddNetworkMenu(IN EFI_HII_HANDLE Handle,IN EFI_FORM_ID NextShowFormId,OUT UINTN * ItemCount)341 IsNeedAddNetworkMenu (
342   IN      EFI_HII_HANDLE      Handle,
343   IN      EFI_FORM_ID         NextShowFormId,
344   OUT     UINTN               *ItemCount
345   )
346 {
347   EFI_STATUS     Status;
348   UINTN          EntryCount;
349   UINTN          Index;
350   EFI_HII_HANDLE HiiDeviceManagerHandle;
351   EFI_HANDLE     DriverHandle;
352   EFI_HANDLE     ControllerHandle;
353   EFI_DEVICE_PATH_PROTOCOL   *DevicePath;
354   EFI_DEVICE_PATH_PROTOCOL   *TmpDevicePath;
355   EFI_DEVICE_PATH_PROTOCOL   *ChildDevicePath;
356   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY   *OpenInfoBuffer;
357   BOOLEAN        IsNeedAdd;
358 
359   HiiDeviceManagerHandle = gDeviceManagerPrivate.HiiHandle;
360   IsNeedAdd  = FALSE;
361   OpenInfoBuffer = NULL;
362   if ((Handle == NULL) || (ItemCount == NULL)) {
363     return FALSE;
364   }
365   *ItemCount = 0;
366 
367   Status = gHiiDatabase->GetPackageListHandle (gHiiDatabase, Handle, &DriverHandle);
368   if (EFI_ERROR (Status)) {
369     return FALSE;
370   }
371   //
372   // Get the device path by the got Driver handle .
373   //
374   Status = gBS->HandleProtocol (DriverHandle, &gEfiDevicePathProtocolGuid, (VOID **) &DevicePath);
375   if (EFI_ERROR (Status)) {
376     return FALSE;
377   }
378   TmpDevicePath = DevicePath;
379 
380   //
381   // Check whether this device path include mac address device path.
382   // If this path has mac address path, get the value whether need
383   // add this info to the menu and return.
384   // Else check more about the child handle devcie path.
385   //
386   if (IsMacAddressDevicePath(TmpDevicePath, NextShowFormId,&IsNeedAdd)) {
387     if ((NETWORK_DEVICE_LIST_FORM_ID == NextShowFormId) && IsNeedAdd) {
388       (*ItemCount) = 1;
389     }
390     return IsNeedAdd;
391   }
392 
393   //
394   // Search whether this path is the controller path, not he child handle path.
395   // And the child handle has the network devcie connected.
396   //
397   TmpDevicePath = DevicePath;
398   Status = gBS->LocateDevicePath(&gEfiDevicePathProtocolGuid, &TmpDevicePath, &ControllerHandle);
399   if (EFI_ERROR (Status)) {
400     return FALSE;
401   }
402 
403   if (!IsDevicePathEnd (TmpDevicePath)) {
404     return FALSE;
405   }
406 
407   //
408   // Retrieve the list of agents that are consuming the specific protocol
409   // on ControllerHandle.
410   // The buffer point by OpenInfoBuffer need be free at this function.
411   //
412   Status = gBS->OpenProtocolInformation (
413                   ControllerHandle,
414                   &gEfiPciIoProtocolGuid,
415                   &OpenInfoBuffer,
416                   &EntryCount
417                   );
418   if (EFI_ERROR (Status)) {
419     return FALSE;
420   }
421 
422   //
423   // Inspect if ChildHandle is one of the agents.
424   //
425   Status = EFI_UNSUPPORTED;
426   for (Index = 0; Index < EntryCount; Index++) {
427     //
428     // Query all the children created by the controller handle's driver
429     //
430     if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
431       Status = gBS->OpenProtocol (
432                       OpenInfoBuffer[Index].ControllerHandle,
433                       &gEfiDevicePathProtocolGuid,
434                       (VOID **) &ChildDevicePath,
435                       NULL,
436                       NULL,
437                       EFI_OPEN_PROTOCOL_GET_PROTOCOL
438                       );
439       if (EFI_ERROR (Status)) {
440         continue;
441       }
442 
443       //
444       // Check whether this device path include mac address device path.
445       //
446       if (!IsMacAddressDevicePath(ChildDevicePath, NextShowFormId,&IsNeedAdd)) {
447         //
448         // If this path not has mac address path, check the other.
449         //
450         continue;
451       } else {
452         //
453         // If need to update the NETWORK_DEVICE_LIST_FORM, try to get more.
454         //
455         if ((NETWORK_DEVICE_LIST_FORM_ID == NextShowFormId)) {
456           if (IsNeedAdd) {
457             (*ItemCount) += 1;
458           }
459           continue;
460         } else {
461           //
462           // If need to update other form, return whether need to add to the menu.
463           //
464           goto Done;
465         }
466       }
467     }
468   }
469 
470 Done:
471   if (OpenInfoBuffer != NULL) {
472     FreePool (OpenInfoBuffer);
473   }
474   return IsNeedAdd;
475 }
476 
477 /**
478   Dynamic create Hii information for Device Manager.
479 
480   @param   NextShowFormId     The FormId which need to be show.
481 
482 **/
483 VOID
CreateDeviceManagerForm(IN EFI_FORM_ID NextShowFormId)484 CreateDeviceManagerForm(
485   IN EFI_FORM_ID      NextShowFormId
486 )
487 {
488   UINTN                       Index;
489   EFI_STRING                  String;
490   EFI_STRING_ID               Token;
491   EFI_STRING_ID               TokenHelp;
492   EFI_HII_HANDLE              *HiiHandles;
493   EFI_HII_HANDLE              HiiHandle;
494   EFI_GUID                    FormSetGuid;
495   VOID                        *StartOpCodeHandle;
496   VOID                        *EndOpCodeHandle;
497   EFI_IFR_GUID_LABEL          *StartLabel;
498   EFI_IFR_GUID_LABEL          *EndLabel;
499   BOOLEAN                     AddNetworkMenu;
500   UINTN                       AddItemCount;
501   UINTN                       NewStringLen;
502   EFI_STRING                  NewStringTitle;
503   CHAR16                      *DevicePathStr;
504   EFI_STRING_ID               DevicePathId;
505   EFI_IFR_FORM_SET            *Buffer;
506   UINTN                       BufferSize;
507   UINT8                       ClassGuidNum;
508   EFI_GUID                    *ClassGuid;
509   UINTN                       TempSize;
510   UINT8                       *Ptr;
511   EFI_STATUS                  Status;
512 
513   TempSize =0;
514   BufferSize = 0;
515   Buffer = NULL;
516 
517   HiiHandle = gDeviceManagerPrivate.HiiHandle;
518   AddNetworkMenu = FALSE;
519   AddItemCount = 0;
520   //
521   // If need show the Network device list form, clear the old save list first.
522   //
523   if ((NextShowFormId == NETWORK_DEVICE_LIST_FORM_ID) && (mMacDeviceList.CurListLen > 0)) {
524     mMacDeviceList.CurListLen = 0;
525   }
526 
527   //
528   // Update the network device form titile.
529   //
530   if (NextShowFormId == NETWORK_DEVICE_FORM_ID) {
531     String = HiiGetString (HiiHandle, STRING_TOKEN (STR_FORM_NETWORK_DEVICE_TITLE), NULL);
532     NewStringLen = StrLen(mSelectedMacAddrString) * 2;
533     NewStringLen += (StrLen(String) + 2) * 2;
534     NewStringTitle = AllocatePool (NewStringLen);
535     UnicodeSPrint (NewStringTitle, NewStringLen, L"%s %s", String, mSelectedMacAddrString);
536     HiiSetString (HiiHandle, STRING_TOKEN (STR_FORM_NETWORK_DEVICE_TITLE), NewStringTitle, NULL);
537     FreePool (String);
538     FreePool (NewStringTitle);
539   }
540 
541   //
542   // Allocate space for creation of UpdateData Buffer
543   //
544   StartOpCodeHandle = HiiAllocateOpCodeHandle ();
545   ASSERT (StartOpCodeHandle != NULL);
546 
547   EndOpCodeHandle = HiiAllocateOpCodeHandle ();
548   ASSERT (EndOpCodeHandle != NULL);
549 
550   //
551   // Create Hii Extend Label OpCode as the start opcode
552   //
553   StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
554   StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
555   //
556   // According to the next show Form id(mNextShowFormId) to decide which form need to update.
557   //
558   StartLabel->Number       = (UINT16) (LABEL_FORM_ID_OFFSET + NextShowFormId);
559 
560   //
561   // Create Hii Extend Label OpCode as the end opcode
562   //
563   EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
564   EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
565   EndLabel->Number       = LABEL_END;
566 
567   //
568   // Get all the Hii handles
569   //
570   HiiHandles = HiiGetHiiHandles (NULL);
571   ASSERT (HiiHandles != NULL);
572 
573   //
574   // Search for formset of each class type
575   //
576   for (Index = 0; HiiHandles[Index] != NULL; Index++) {
577     Status = HiiGetFormSetFromHiiHandle(HiiHandles[Index], &Buffer,&BufferSize);
578     if (EFI_ERROR (Status)){
579       continue;
580     }
581     Ptr = (UINT8 *)Buffer;
582     while(TempSize < BufferSize)  {
583       TempSize += ((EFI_IFR_OP_HEADER *) Ptr)->Length;
584       if (((EFI_IFR_OP_HEADER *) Ptr)->Length <= OFFSET_OF (EFI_IFR_FORM_SET, Flags)){
585         Ptr += ((EFI_IFR_OP_HEADER *) Ptr)->Length;
586         continue;
587       }
588 
589       ClassGuidNum = (UINT8) (((EFI_IFR_FORM_SET *)Ptr)->Flags & 0x3);
590       ClassGuid = (EFI_GUID *) (VOID *)(Ptr + sizeof (EFI_IFR_FORM_SET));
591       while (ClassGuidNum-- > 0) {
592         if (CompareGuid (&gEfiHiiPlatformSetupFormsetGuid, ClassGuid)== 0) {
593           ClassGuid ++;
594           continue;
595         }
596 
597         String = HiiGetString (HiiHandles[Index], ((EFI_IFR_FORM_SET *)Ptr)->FormSetTitle, NULL);
598         if (String == NULL) {
599           String = HiiGetString (HiiHandle, STRING_TOKEN (STR_MISSING_STRING), NULL);
600           ASSERT (String != NULL);
601         }
602         Token = HiiSetString (HiiHandle, 0, String, NULL);
603         FreePool (String);
604 
605         String = HiiGetString (HiiHandles[Index], ((EFI_IFR_FORM_SET *)Ptr)->Help, NULL);
606         if (String == NULL) {
607           String = HiiGetString (HiiHandle, STRING_TOKEN (STR_MISSING_STRING), NULL);
608           ASSERT (String != NULL);
609         }
610         TokenHelp = HiiSetString (HiiHandle, 0, String, NULL);
611         FreePool (String);
612 
613         FormSetGuid = ((EFI_IFR_FORM_SET *)Ptr)->Guid;
614 
615         //
616         // Network device process
617         //
618         if (IsNeedAddNetworkMenu (HiiHandles[Index], NextShowFormId,&AddItemCount)) {
619           if (NextShowFormId == DEVICE_MANAGER_FORM_ID) {
620             //
621             // Only show one menu item "Network Config" in the device manger form.
622             //
623             if (!AddNetworkMenu) {
624               AddNetworkMenu = TRUE;
625               HiiCreateGotoOpCode (
626                 StartOpCodeHandle,
627                 NETWORK_DEVICE_LIST_FORM_ID,
628                 STRING_TOKEN (STR_FORM_NETWORK_DEVICE_LIST_TITLE),
629                 STRING_TOKEN (STR_FORM_NETWORK_DEVICE_LIST_HELP),
630                 EFI_IFR_FLAG_CALLBACK,
631                 (EFI_QUESTION_ID) QUESTION_NETWORK_DEVICE_ID
632               );
633             }
634           } else if (NextShowFormId == NETWORK_DEVICE_LIST_FORM_ID) {
635             //
636             // In network device list form, same mac address device only show one menu.
637             //
638             while (AddItemCount > 0) {
639               HiiCreateGotoOpCode (
640                 StartOpCodeHandle,
641                 NETWORK_DEVICE_FORM_ID,
642                 mMacDeviceList.NodeList[mMacDeviceList.CurListLen - AddItemCount].PromptId,
643                 STRING_TOKEN (STR_NETWORK_DEVICE_HELP),
644                 EFI_IFR_FLAG_CALLBACK,
645                 mMacDeviceList.NodeList[mMacDeviceList.CurListLen - AddItemCount].QuestionId
646               );
647               AddItemCount -= 1;
648             }
649           } else if (NextShowFormId == NETWORK_DEVICE_FORM_ID) {
650             //
651             // In network device form, only the selected mac address device need to be show.
652             //
653             DevicePathStr = DmExtractDevicePathFromHiiHandle(HiiHandles[Index]);
654             DevicePathId  = 0;
655             if (DevicePathStr != NULL){
656               DevicePathId =  HiiSetString (HiiHandle, 0, DevicePathStr, NULL);
657               FreePool(DevicePathStr);
658             }
659             HiiCreateGotoExOpCode (
660               StartOpCodeHandle,
661               0,
662               Token,
663               TokenHelp,
664               0,
665               (EFI_QUESTION_ID) (Index + DEVICE_KEY_OFFSET),
666               0,
667               &FormSetGuid,
668               DevicePathId
669             );
670           }
671         } else {
672           //
673           // Not network device process, only need to show at device manger form.
674           //
675           if (NextShowFormId == DEVICE_MANAGER_FORM_ID) {
676             DevicePathStr = DmExtractDevicePathFromHiiHandle(HiiHandles[Index]);
677             DevicePathId  = 0;
678             if (DevicePathStr != NULL){
679               DevicePathId =  HiiSetString (HiiHandle, 0, DevicePathStr, NULL);
680               FreePool(DevicePathStr);
681             }
682             HiiCreateGotoExOpCode (
683               StartOpCodeHandle,
684               0,
685               Token,
686               TokenHelp,
687               0,
688               (EFI_QUESTION_ID) (Index + DEVICE_KEY_OFFSET),
689               0,
690               &FormSetGuid,
691               DevicePathId
692             );
693           }
694         }
695         break;
696       }
697 
698       Ptr += ((EFI_IFR_OP_HEADER *) Ptr)->Length;
699     }
700     FreePool(Buffer);
701     Buffer = NULL;
702     TempSize = 0;
703     BufferSize = 0;
704   }
705 
706   HiiUpdateForm (
707     HiiHandle,
708     &mDeviceManagerGuid,
709     NextShowFormId,
710     StartOpCodeHandle,
711     EndOpCodeHandle
712     );
713 
714   HiiFreeOpCodeHandle (StartOpCodeHandle);
715   HiiFreeOpCodeHandle (EndOpCodeHandle);
716   FreePool (HiiHandles);
717 }
718 
719 /**
720   This function allows a caller to extract the current configuration for one
721   or more named elements from the target driver.
722 
723 
724   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
725   @param Request         A null-terminated Unicode string in <ConfigRequest> format.
726   @param Progress        On return, points to a character in the Request string.
727                          Points to the string's null terminator if request was successful.
728                          Points to the most recent '&' before the first failing name/value
729                          pair (or the beginning of the string if the failure is in the
730                          first name/value pair) if the request was not successful.
731   @param Results         A null-terminated Unicode string in <ConfigAltResp> format which
732                          has all values filled in for the names in the Request string.
733                          String to be allocated by the called function.
734 
735   @retval  EFI_SUCCESS            The Results is filled with the requested values.
736   @retval  EFI_OUT_OF_RESOURCES   Not enough memory to store the results.
737   @retval  EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.
738   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
739 
740 **/
741 EFI_STATUS
742 EFIAPI
DeviceManagerExtractConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Request,OUT EFI_STRING * Progress,OUT EFI_STRING * Results)743 DeviceManagerExtractConfig (
744   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
745   IN  CONST EFI_STRING                       Request,
746   OUT EFI_STRING                             *Progress,
747   OUT EFI_STRING                             *Results
748   )
749 {
750   if (Progress == NULL || Results == NULL) {
751     return EFI_INVALID_PARAMETER;
752   }
753   *Progress = Request;
754   return EFI_NOT_FOUND;
755 }
756 
757 /**
758   This function processes the results of changes in configuration.
759 
760   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
761   @param Configuration   A null-terminated Unicode string in <ConfigResp> format.
762   @param Progress        A pointer to a string filled in with the offset of the most
763                          recent '&' before the first failing name/value pair (or the
764                          beginning of the string if the failure is in the first
765                          name/value pair) or the terminating NULL if all was successful.
766 
767   @retval  EFI_SUCCESS            The Results is processed successfully.
768   @retval  EFI_INVALID_PARAMETER  Configuration is NULL.
769   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
770 
771 **/
772 EFI_STATUS
773 EFIAPI
DeviceManagerRouteConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Configuration,OUT EFI_STRING * Progress)774 DeviceManagerRouteConfig (
775   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
776   IN  CONST EFI_STRING                       Configuration,
777   OUT EFI_STRING                             *Progress
778   )
779 {
780   if (Configuration == NULL || Progress == NULL) {
781     return EFI_INVALID_PARAMETER;
782   }
783 
784   *Progress = Configuration;
785 
786   return EFI_NOT_FOUND;
787 }
788 
789 /**
790   This function is invoked if user selected a interactive opcode from Device Manager's
791   Formset. If user set VBIOS, the new value is saved to EFI variable.
792 
793   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
794   @param Action          Specifies the type of action taken by the browser.
795   @param QuestionId      A unique value which is sent to the original exporting driver
796                          so that it can identify the type of data to expect.
797   @param Type            The type of value for the question.
798   @param Value           A pointer to the data being sent to the original exporting driver.
799   @param ActionRequest   On return, points to the action requested by the callback function.
800 
801   @retval  EFI_SUCCESS           The callback successfully handled the action.
802   @retval  EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
803 
804 **/
805 EFI_STATUS
806 EFIAPI
DeviceManagerCallback(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN EFI_BROWSER_ACTION Action,IN EFI_QUESTION_ID QuestionId,IN UINT8 Type,IN EFI_IFR_TYPE_VALUE * Value,OUT EFI_BROWSER_ACTION_REQUEST * ActionRequest)807 DeviceManagerCallback (
808   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
809   IN  EFI_BROWSER_ACTION                     Action,
810   IN  EFI_QUESTION_ID                        QuestionId,
811   IN  UINT8                                  Type,
812   IN  EFI_IFR_TYPE_VALUE                     *Value,
813   OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
814   )
815 {
816   UINTN CurIndex;
817 
818   if (Action != EFI_BROWSER_ACTION_CHANGING) {
819     //
820     // Do nothing for other UEFI Action. Only do call back when data is changed.
821     //
822     return EFI_UNSUPPORTED;
823   }
824   if ((Value == NULL) || (ActionRequest == NULL)) {
825     return EFI_INVALID_PARAMETER;
826   }
827   if ((QuestionId < MAX_KEY_SECTION_LEN + NETWORK_DEVICE_LIST_KEY_OFFSET) && (QuestionId >= NETWORK_DEVICE_LIST_KEY_OFFSET)) {
828     //
829     // If user select the mac address, need to record mac address string to support next form show.
830     //
831     for (CurIndex = 0; CurIndex < mMacDeviceList.CurListLen; CurIndex ++) {
832       if (mMacDeviceList.NodeList[CurIndex].QuestionId == QuestionId) {
833          mSelectedMacAddrString = HiiGetString (gDeviceManagerPrivate.HiiHandle, mMacDeviceList.NodeList[CurIndex].PromptId, NULL);
834       }
835     }
836     CreateDeviceManagerForm(NETWORK_DEVICE_FORM_ID);
837   } else if(QuestionId == QUESTION_NETWORK_DEVICE_ID){
838     CreateDeviceManagerForm(NETWORK_DEVICE_LIST_FORM_ID);
839   }
840 
841   return EFI_SUCCESS;
842 }
843 
844 /**
845   Install Boot Manager Menu driver.
846 
847   @param ImageHandle     The image handle.
848   @param SystemTable     The system table.
849 
850   @retval  EFI_SUCEESS  Install Boot manager menu success.
851   @retval  Other        Return error status.
852 
853 **/
854 EFI_STATUS
855 EFIAPI
DeviceManagerLibConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)856 DeviceManagerLibConstructor (
857   IN EFI_HANDLE                            ImageHandle,
858   IN EFI_SYSTEM_TABLE                      *SystemTable
859 )
860 {
861   EFI_STATUS                  Status;
862 
863   gDeviceManagerPrivate.DriverHandle = NULL;
864   Status = gBS->InstallMultipleProtocolInterfaces (
865                   &gDeviceManagerPrivate.DriverHandle,
866                   &gEfiDevicePathProtocolGuid,
867                   &mDeviceManagerHiiVendorDevicePath,
868                   &gEfiHiiConfigAccessProtocolGuid,
869                   &gDeviceManagerPrivate.ConfigAccess,
870                   NULL
871                   );
872   ASSERT_EFI_ERROR (Status);
873 
874   //
875   // Publish our HII data.
876   //
877   gDeviceManagerPrivate.HiiHandle = HiiAddPackages (
878                   &mDeviceManagerGuid,
879                   gDeviceManagerPrivate.DriverHandle,
880                   DeviceManagerVfrBin,
881                   DeviceManagerLibStrings,
882                   NULL
883                   );
884   ASSERT (gDeviceManagerPrivate.HiiHandle != NULL);
885 
886   //
887   // Update boot manager page
888   //
889   CreateDeviceManagerForm (DEVICE_MANAGER_FORM_ID);
890 
891   return EFI_SUCCESS;
892 }
893 
894 /**
895   Unloads the application and its installed protocol.
896 
897   @param  ImageHandle     Handle that identifies the image to be unloaded.
898   @param  SystemTable     The system table.
899 
900   @retval EFI_SUCCESS           The image has been unloaded.
901 **/
902 EFI_STATUS
903 EFIAPI
DeviceManagerLibDestructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)904 DeviceManagerLibDestructor(
905   IN EFI_HANDLE                            ImageHandle,
906   IN EFI_SYSTEM_TABLE                      *SystemTable
907 )
908 {
909   EFI_STATUS                  Status;
910 
911   Status = gBS->UninstallMultipleProtocolInterfaces (
912                   gDeviceManagerPrivate.DriverHandle,
913                   &gEfiDevicePathProtocolGuid,
914                   &mDeviceManagerHiiVendorDevicePath,
915                   &gEfiHiiConfigAccessProtocolGuid,
916                   &gDeviceManagerPrivate.ConfigAccess,
917                   NULL
918                   );
919   ASSERT_EFI_ERROR (Status);
920 
921   HiiRemovePackages (gDeviceManagerPrivate.HiiHandle);
922 
923   return EFI_SUCCESS;
924 }
925 
926