1/** @file
2The device manager reference implementation
3
4Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution.  The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15#include "DeviceManager.h"
16
17DEVICE_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
30EFI_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//
36EFI_STRING  mSelectedMacAddrString;
37
38//
39// The Mac Address show in the NETWORK_DEVICE_LIST_FORM_ID
40//
41MAC_ADDRESS_NODE_LIST  mMacDeviceList;
42
43HII_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**/
77CHAR16 *
78DmExtractDevicePathFromHiiHandle (
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**/
109BOOLEAN
110GetMacAddressString(
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**/
191BOOLEAN
192AddIdToMacDeviceList (
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**/
266BOOLEAN
267IsMacAddressDevicePath (
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**/
340BOOLEAN
341IsNeedAddNetworkMenu (
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_HANDLE     DriverHandle;
351  EFI_HANDLE     ControllerHandle;
352  EFI_DEVICE_PATH_PROTOCOL   *DevicePath;
353  EFI_DEVICE_PATH_PROTOCOL   *TmpDevicePath;
354  EFI_DEVICE_PATH_PROTOCOL   *ChildDevicePath;
355  EFI_OPEN_PROTOCOL_INFORMATION_ENTRY   *OpenInfoBuffer;
356  BOOLEAN        IsNeedAdd;
357
358  IsNeedAdd  = FALSE;
359  OpenInfoBuffer = NULL;
360  if ((Handle == NULL) || (ItemCount == NULL)) {
361    return FALSE;
362  }
363  *ItemCount = 0;
364
365  Status = gHiiDatabase->GetPackageListHandle (gHiiDatabase, Handle, &DriverHandle);
366  if (EFI_ERROR (Status)) {
367    return FALSE;
368  }
369  //
370  // Get the device path by the got Driver handle .
371  //
372  Status = gBS->HandleProtocol (DriverHandle, &gEfiDevicePathProtocolGuid, (VOID **) &DevicePath);
373  if (EFI_ERROR (Status)) {
374    return FALSE;
375  }
376  TmpDevicePath = DevicePath;
377
378  //
379  // Check whether this device path include mac address device path.
380  // If this path has mac address path, get the value whether need
381  // add this info to the menu and return.
382  // Else check more about the child handle devcie path.
383  //
384  if (IsMacAddressDevicePath(TmpDevicePath, NextShowFormId,&IsNeedAdd)) {
385    if ((NETWORK_DEVICE_LIST_FORM_ID == NextShowFormId) && IsNeedAdd) {
386      (*ItemCount) = 1;
387    }
388    return IsNeedAdd;
389  }
390
391  //
392  // Search whether this path is the controller path, not he child handle path.
393  // And the child handle has the network devcie connected.
394  //
395  TmpDevicePath = DevicePath;
396  Status = gBS->LocateDevicePath(&gEfiDevicePathProtocolGuid, &TmpDevicePath, &ControllerHandle);
397  if (EFI_ERROR (Status)) {
398    return FALSE;
399  }
400
401  if (!IsDevicePathEnd (TmpDevicePath)) {
402    return FALSE;
403  }
404
405  //
406  // Retrieve the list of agents that are consuming the specific protocol
407  // on ControllerHandle.
408  // The buffer point by OpenInfoBuffer need be free at this function.
409  //
410  Status = gBS->OpenProtocolInformation (
411                  ControllerHandle,
412                  &gEfiPciIoProtocolGuid,
413                  &OpenInfoBuffer,
414                  &EntryCount
415                  );
416  if (EFI_ERROR (Status)) {
417    return FALSE;
418  }
419
420  //
421  // Inspect if ChildHandle is one of the agents.
422  //
423  Status = EFI_UNSUPPORTED;
424  for (Index = 0; Index < EntryCount; Index++) {
425    //
426    // Query all the children created by the controller handle's driver
427    //
428    if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
429      Status = gBS->OpenProtocol (
430                      OpenInfoBuffer[Index].ControllerHandle,
431                      &gEfiDevicePathProtocolGuid,
432                      (VOID **) &ChildDevicePath,
433                      NULL,
434                      NULL,
435                      EFI_OPEN_PROTOCOL_GET_PROTOCOL
436                      );
437      if (EFI_ERROR (Status)) {
438        continue;
439      }
440
441      //
442      // Check whether this device path include mac address device path.
443      //
444      if (!IsMacAddressDevicePath(ChildDevicePath, NextShowFormId,&IsNeedAdd)) {
445        //
446        // If this path not has mac address path, check the other.
447        //
448        continue;
449      } else {
450        //
451        // If need to update the NETWORK_DEVICE_LIST_FORM, try to get more.
452        //
453        if ((NETWORK_DEVICE_LIST_FORM_ID == NextShowFormId)) {
454          if (IsNeedAdd) {
455            (*ItemCount) += 1;
456          }
457          continue;
458        } else {
459          //
460          // If need to update other form, return whether need to add to the menu.
461          //
462          goto Done;
463        }
464      }
465    }
466  }
467
468Done:
469  if (OpenInfoBuffer != NULL) {
470    FreePool (OpenInfoBuffer);
471  }
472  return IsNeedAdd;
473}
474
475/**
476  Dynamic create Hii information for Device Manager.
477
478  @param   NextShowFormId     The FormId which need to be show.
479
480**/
481VOID
482CreateDeviceManagerForm(
483  IN EFI_FORM_ID      NextShowFormId
484)
485{
486  UINTN                       Index;
487  EFI_STRING                  String;
488  EFI_STRING_ID               Token;
489  EFI_STRING_ID               TokenHelp;
490  EFI_HII_HANDLE              *HiiHandles;
491  EFI_HII_HANDLE              HiiHandle;
492  EFI_GUID                    FormSetGuid;
493  VOID                        *StartOpCodeHandle;
494  VOID                        *EndOpCodeHandle;
495  EFI_IFR_GUID_LABEL          *StartLabel;
496  EFI_IFR_GUID_LABEL          *EndLabel;
497  BOOLEAN                     AddNetworkMenu;
498  UINTN                       AddItemCount;
499  UINTN                       NewStringLen;
500  EFI_STRING                  NewStringTitle;
501  CHAR16                      *DevicePathStr;
502  EFI_STRING_ID               DevicePathId;
503  EFI_IFR_FORM_SET            *Buffer;
504  UINTN                       BufferSize;
505  UINT8                       ClassGuidNum;
506  EFI_GUID                    *ClassGuid;
507  UINTN                       TempSize;
508  UINT8                       *Ptr;
509  EFI_STATUS                  Status;
510
511  TempSize =0;
512  BufferSize = 0;
513  Buffer = NULL;
514
515  HiiHandle = gDeviceManagerPrivate.HiiHandle;
516  AddNetworkMenu = FALSE;
517  AddItemCount = 0;
518  //
519  // If need show the Network device list form, clear the old save list first.
520  //
521  if ((NextShowFormId == NETWORK_DEVICE_LIST_FORM_ID) && (mMacDeviceList.CurListLen > 0)) {
522    mMacDeviceList.CurListLen = 0;
523  }
524
525  //
526  // Update the network device form titile.
527  //
528  if (NextShowFormId == NETWORK_DEVICE_FORM_ID) {
529    String = HiiGetString (HiiHandle, STRING_TOKEN (STR_FORM_NETWORK_DEVICE_TITLE), NULL);
530    NewStringLen = StrLen(mSelectedMacAddrString) * 2;
531    NewStringLen += (StrLen(String) + 2) * 2;
532    NewStringTitle = AllocatePool (NewStringLen);
533    UnicodeSPrint (NewStringTitle, NewStringLen, L"%s %s", String, mSelectedMacAddrString);
534    HiiSetString (HiiHandle, STRING_TOKEN (STR_FORM_NETWORK_DEVICE_TITLE), NewStringTitle, NULL);
535    FreePool (String);
536    FreePool (NewStringTitle);
537  }
538
539  //
540  // Allocate space for creation of UpdateData Buffer
541  //
542  StartOpCodeHandle = HiiAllocateOpCodeHandle ();
543  ASSERT (StartOpCodeHandle != NULL);
544
545  EndOpCodeHandle = HiiAllocateOpCodeHandle ();
546  ASSERT (EndOpCodeHandle != NULL);
547
548  //
549  // Create Hii Extend Label OpCode as the start opcode
550  //
551  StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
552  StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
553  //
554  // According to the next show Form id(mNextShowFormId) to decide which form need to update.
555  //
556  StartLabel->Number       = (UINT16) (LABEL_FORM_ID_OFFSET + NextShowFormId);
557
558  //
559  // Create Hii Extend Label OpCode as the end opcode
560  //
561  EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
562  EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
563  EndLabel->Number       = LABEL_END;
564
565  //
566  // Get all the Hii handles
567  //
568  HiiHandles = HiiGetHiiHandles (NULL);
569  ASSERT (HiiHandles != NULL);
570
571  //
572  // Search for formset of each class type
573  //
574  for (Index = 0; HiiHandles[Index] != NULL; Index++) {
575    Status = HiiGetFormSetFromHiiHandle(HiiHandles[Index], &Buffer,&BufferSize);
576    if (EFI_ERROR (Status)){
577      continue;
578    }
579    Ptr = (UINT8 *)Buffer;
580    while(TempSize < BufferSize)  {
581      TempSize += ((EFI_IFR_OP_HEADER *) Ptr)->Length;
582      if (((EFI_IFR_OP_HEADER *) Ptr)->Length <= OFFSET_OF (EFI_IFR_FORM_SET, Flags)){
583        Ptr += ((EFI_IFR_OP_HEADER *) Ptr)->Length;
584        continue;
585      }
586
587      ClassGuidNum = (UINT8) (((EFI_IFR_FORM_SET *)Ptr)->Flags & 0x3);
588      ClassGuid = (EFI_GUID *) (VOID *)(Ptr + sizeof (EFI_IFR_FORM_SET));
589      while (ClassGuidNum-- > 0) {
590        if (CompareGuid (&gEfiHiiPlatformSetupFormsetGuid, ClassGuid)== 0) {
591          ClassGuid ++;
592          continue;
593        }
594
595        String = HiiGetString (HiiHandles[Index], ((EFI_IFR_FORM_SET *)Ptr)->FormSetTitle, NULL);
596        if (String == NULL) {
597          String = HiiGetString (HiiHandle, STRING_TOKEN (STR_MISSING_STRING), NULL);
598          ASSERT (String != NULL);
599        }
600        Token = HiiSetString (HiiHandle, 0, String, NULL);
601        FreePool (String);
602
603        String = HiiGetString (HiiHandles[Index], ((EFI_IFR_FORM_SET *)Ptr)->Help, NULL);
604        if (String == NULL) {
605          String = HiiGetString (HiiHandle, STRING_TOKEN (STR_MISSING_STRING), NULL);
606          ASSERT (String != NULL);
607        }
608        TokenHelp = HiiSetString (HiiHandle, 0, String, NULL);
609        FreePool (String);
610
611        FormSetGuid = ((EFI_IFR_FORM_SET *)Ptr)->Guid;
612
613        //
614        // Network device process
615        //
616        if (IsNeedAddNetworkMenu (HiiHandles[Index], NextShowFormId,&AddItemCount)) {
617          if (NextShowFormId == DEVICE_MANAGER_FORM_ID) {
618            //
619            // Only show one menu item "Network Config" in the device manger form.
620            //
621            if (!AddNetworkMenu) {
622              AddNetworkMenu = TRUE;
623              HiiCreateGotoOpCode (
624                StartOpCodeHandle,
625                NETWORK_DEVICE_LIST_FORM_ID,
626                STRING_TOKEN (STR_FORM_NETWORK_DEVICE_LIST_TITLE),
627                STRING_TOKEN (STR_FORM_NETWORK_DEVICE_LIST_HELP),
628                EFI_IFR_FLAG_CALLBACK,
629                (EFI_QUESTION_ID) QUESTION_NETWORK_DEVICE_ID
630              );
631            }
632          } else if (NextShowFormId == NETWORK_DEVICE_LIST_FORM_ID) {
633            //
634            // In network device list form, same mac address device only show one menu.
635            //
636            while (AddItemCount > 0) {
637              HiiCreateGotoOpCode (
638                StartOpCodeHandle,
639                NETWORK_DEVICE_FORM_ID,
640                mMacDeviceList.NodeList[mMacDeviceList.CurListLen - AddItemCount].PromptId,
641                STRING_TOKEN (STR_NETWORK_DEVICE_HELP),
642                EFI_IFR_FLAG_CALLBACK,
643                mMacDeviceList.NodeList[mMacDeviceList.CurListLen - AddItemCount].QuestionId
644              );
645              AddItemCount -= 1;
646            }
647          } else if (NextShowFormId == NETWORK_DEVICE_FORM_ID) {
648            //
649            // In network device form, only the selected mac address device need to be show.
650            //
651            DevicePathStr = DmExtractDevicePathFromHiiHandle(HiiHandles[Index]);
652            DevicePathId  = 0;
653            if (DevicePathStr != NULL){
654              DevicePathId =  HiiSetString (HiiHandle, 0, DevicePathStr, NULL);
655              FreePool(DevicePathStr);
656            }
657            HiiCreateGotoExOpCode (
658              StartOpCodeHandle,
659              0,
660              Token,
661              TokenHelp,
662              0,
663              (EFI_QUESTION_ID) (Index + DEVICE_KEY_OFFSET),
664              0,
665              &FormSetGuid,
666              DevicePathId
667            );
668          }
669        } else {
670          //
671          // Not network device process, only need to show at device manger form.
672          //
673          if (NextShowFormId == DEVICE_MANAGER_FORM_ID) {
674            DevicePathStr = DmExtractDevicePathFromHiiHandle(HiiHandles[Index]);
675            DevicePathId  = 0;
676            if (DevicePathStr != NULL){
677              DevicePathId =  HiiSetString (HiiHandle, 0, DevicePathStr, NULL);
678              FreePool(DevicePathStr);
679            }
680            HiiCreateGotoExOpCode (
681              StartOpCodeHandle,
682              0,
683              Token,
684              TokenHelp,
685              0,
686              (EFI_QUESTION_ID) (Index + DEVICE_KEY_OFFSET),
687              0,
688              &FormSetGuid,
689              DevicePathId
690            );
691          }
692        }
693        break;
694      }
695
696      Ptr += ((EFI_IFR_OP_HEADER *) Ptr)->Length;
697    }
698    FreePool(Buffer);
699    Buffer = NULL;
700    TempSize = 0;
701    BufferSize = 0;
702  }
703
704  HiiUpdateForm (
705    HiiHandle,
706    &mDeviceManagerGuid,
707    NextShowFormId,
708    StartOpCodeHandle,
709    EndOpCodeHandle
710    );
711
712  HiiFreeOpCodeHandle (StartOpCodeHandle);
713  HiiFreeOpCodeHandle (EndOpCodeHandle);
714  FreePool (HiiHandles);
715}
716
717/**
718  This function allows a caller to extract the current configuration for one
719  or more named elements from the target driver.
720
721
722  @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
723  @param Request         A null-terminated Unicode string in <ConfigRequest> format.
724  @param Progress        On return, points to a character in the Request string.
725                         Points to the string's null terminator if request was successful.
726                         Points to the most recent '&' before the first failing name/value
727                         pair (or the beginning of the string if the failure is in the
728                         first name/value pair) if the request was not successful.
729  @param Results         A null-terminated Unicode string in <ConfigAltResp> format which
730                         has all values filled in for the names in the Request string.
731                         String to be allocated by the called function.
732
733  @retval  EFI_SUCCESS            The Results is filled with the requested values.
734  @retval  EFI_OUT_OF_RESOURCES   Not enough memory to store the results.
735  @retval  EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.
736  @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
737
738**/
739EFI_STATUS
740EFIAPI
741DeviceManagerExtractConfig (
742  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
743  IN  CONST EFI_STRING                       Request,
744  OUT EFI_STRING                             *Progress,
745  OUT EFI_STRING                             *Results
746  )
747{
748  if (Progress == NULL || Results == NULL) {
749    return EFI_INVALID_PARAMETER;
750  }
751  *Progress = Request;
752  return EFI_NOT_FOUND;
753}
754
755/**
756  This function processes the results of changes in configuration.
757
758  @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
759  @param Configuration   A null-terminated Unicode string in <ConfigResp> format.
760  @param Progress        A pointer to a string filled in with the offset of the most
761                         recent '&' before the first failing name/value pair (or the
762                         beginning of the string if the failure is in the first
763                         name/value pair) or the terminating NULL if all was successful.
764
765  @retval  EFI_SUCCESS            The Results is processed successfully.
766  @retval  EFI_INVALID_PARAMETER  Configuration is NULL.
767  @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
768
769**/
770EFI_STATUS
771EFIAPI
772DeviceManagerRouteConfig (
773  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
774  IN  CONST EFI_STRING                       Configuration,
775  OUT EFI_STRING                             *Progress
776  )
777{
778  if (Configuration == NULL || Progress == NULL) {
779    return EFI_INVALID_PARAMETER;
780  }
781
782  *Progress = Configuration;
783
784  return EFI_NOT_FOUND;
785}
786
787/**
788  This function is invoked if user selected a interactive opcode from Device Manager's
789  Formset. If user set VBIOS, the new value is saved to EFI variable.
790
791  @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
792  @param Action          Specifies the type of action taken by the browser.
793  @param QuestionId      A unique value which is sent to the original exporting driver
794                         so that it can identify the type of data to expect.
795  @param Type            The type of value for the question.
796  @param Value           A pointer to the data being sent to the original exporting driver.
797  @param ActionRequest   On return, points to the action requested by the callback function.
798
799  @retval  EFI_SUCCESS           The callback successfully handled the action.
800  @retval  EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
801
802**/
803EFI_STATUS
804EFIAPI
805DeviceManagerCallback (
806  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
807  IN  EFI_BROWSER_ACTION                     Action,
808  IN  EFI_QUESTION_ID                        QuestionId,
809  IN  UINT8                                  Type,
810  IN  EFI_IFR_TYPE_VALUE                     *Value,
811  OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
812  )
813{
814  UINTN CurIndex;
815
816  if (Action != EFI_BROWSER_ACTION_CHANGING) {
817    //
818    // Do nothing for other UEFI Action. Only do call back when data is changed.
819    //
820    return EFI_UNSUPPORTED;
821  }
822  if ((Value == NULL) || (ActionRequest == NULL)) {
823    return EFI_INVALID_PARAMETER;
824  }
825  if ((QuestionId < MAX_KEY_SECTION_LEN + NETWORK_DEVICE_LIST_KEY_OFFSET) && (QuestionId >= NETWORK_DEVICE_LIST_KEY_OFFSET)) {
826    //
827    // If user select the mac address, need to record mac address string to support next form show.
828    //
829    for (CurIndex = 0; CurIndex < mMacDeviceList.CurListLen; CurIndex ++) {
830      if (mMacDeviceList.NodeList[CurIndex].QuestionId == QuestionId) {
831         mSelectedMacAddrString = HiiGetString (gDeviceManagerPrivate.HiiHandle, mMacDeviceList.NodeList[CurIndex].PromptId, NULL);
832      }
833    }
834    CreateDeviceManagerForm(NETWORK_DEVICE_FORM_ID);
835  } else if(QuestionId == QUESTION_NETWORK_DEVICE_ID){
836    CreateDeviceManagerForm(NETWORK_DEVICE_LIST_FORM_ID);
837  }
838
839  return EFI_SUCCESS;
840}
841
842/**
843  Install Boot Manager Menu driver.
844
845  @param ImageHandle     The image handle.
846  @param SystemTable     The system table.
847
848  @retval  EFI_SUCEESS  Install Boot manager menu success.
849  @retval  Other        Return error status.
850
851**/
852EFI_STATUS
853EFIAPI
854DeviceManagerUiLibConstructor (
855  IN EFI_HANDLE                            ImageHandle,
856  IN EFI_SYSTEM_TABLE                      *SystemTable
857)
858{
859  EFI_STATUS                  Status;
860
861  gDeviceManagerPrivate.DriverHandle = NULL;
862  Status = gBS->InstallMultipleProtocolInterfaces (
863                  &gDeviceManagerPrivate.DriverHandle,
864                  &gEfiDevicePathProtocolGuid,
865                  &mDeviceManagerHiiVendorDevicePath,
866                  &gEfiHiiConfigAccessProtocolGuid,
867                  &gDeviceManagerPrivate.ConfigAccess,
868                  NULL
869                  );
870  ASSERT_EFI_ERROR (Status);
871
872  //
873  // Publish our HII data.
874  //
875  gDeviceManagerPrivate.HiiHandle = HiiAddPackages (
876                  &mDeviceManagerGuid,
877                  gDeviceManagerPrivate.DriverHandle,
878                  DeviceManagerVfrBin,
879                  DeviceManagerUiLibStrings,
880                  NULL
881                  );
882  ASSERT (gDeviceManagerPrivate.HiiHandle != NULL);
883
884  //
885  // Update boot manager page
886  //
887  CreateDeviceManagerForm (DEVICE_MANAGER_FORM_ID);
888
889  return EFI_SUCCESS;
890}
891
892/**
893  Unloads the application and its installed protocol.
894
895  @param  ImageHandle     Handle that identifies the image to be unloaded.
896  @param  SystemTable     The system table.
897
898  @retval EFI_SUCCESS           The image has been unloaded.
899**/
900EFI_STATUS
901EFIAPI
902DeviceManagerUiLibDestructor(
903  IN EFI_HANDLE                            ImageHandle,
904  IN EFI_SYSTEM_TABLE                      *SystemTable
905)
906{
907  EFI_STATUS                  Status;
908
909  Status = gBS->UninstallMultipleProtocolInterfaces (
910                  gDeviceManagerPrivate.DriverHandle,
911                  &gEfiDevicePathProtocolGuid,
912                  &mDeviceManagerHiiVendorDevicePath,
913                  &gEfiHiiConfigAccessProtocolGuid,
914                  &gDeviceManagerPrivate.ConfigAccess,
915                  NULL
916                  );
917  ASSERT_EFI_ERROR (Status);
918
919  HiiRemovePackages (gDeviceManagerPrivate.HiiHandle);
920
921  return EFI_SUCCESS;
922}
923
924