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_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
470Done:
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**/
483VOID
484CreateDeviceManagerForm(
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**/
741EFI_STATUS
742EFIAPI
743DeviceManagerExtractConfig (
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**/
772EFI_STATUS
773EFIAPI
774DeviceManagerRouteConfig (
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**/
805EFI_STATUS
806EFIAPI
807DeviceManagerCallback (
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**/
854EFI_STATUS
855EFIAPI
856DeviceManagerLibConstructor (
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**/
902EFI_STATUS
903EFIAPI
904DeviceManagerLibDestructor(
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