Home | History | Annotate | Download | only in DeviceManagerLib
      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 *
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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