Home | History | Annotate | Download | only in ConPlatformDxe
      1 /** @file
      2   Console Platform DXE Driver, install Console Device Guids and update Console
      3   Environment Variables.
      4 
      5 Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "ConPlatform.h"
     17 
     18 
     19 EFI_DRIVER_BINDING_PROTOCOL gConPlatformTextInDriverBinding = {
     20   ConPlatformTextInDriverBindingSupported,
     21   ConPlatformTextInDriverBindingStart,
     22   ConPlatformTextInDriverBindingStop,
     23   0xa,
     24   NULL,
     25   NULL
     26 };
     27 
     28 EFI_DRIVER_BINDING_PROTOCOL gConPlatformTextOutDriverBinding = {
     29   ConPlatformTextOutDriverBindingSupported,
     30   ConPlatformTextOutDriverBindingStart,
     31   ConPlatformTextOutDriverBindingStop,
     32   0xa,
     33   NULL,
     34   NULL
     35 };
     36 
     37 /**
     38   Entrypoint of this module.
     39 
     40   This function is the entrypoint of this module. It installs Driver Binding
     41   Protocols together with Component Name Protocols.
     42 
     43   @param  ImageHandle       The firmware allocated handle for the EFI image.
     44   @param  SystemTable       A pointer to the EFI System Table.
     45 
     46   @retval EFI_SUCCESS       The entry point is executed successfully.
     47 
     48 **/
     49 EFI_STATUS
     50 EFIAPI
     51 InitializeConPlatform(
     52   IN EFI_HANDLE           ImageHandle,
     53   IN EFI_SYSTEM_TABLE     *SystemTable
     54   )
     55 {
     56   EFI_STATUS              Status;
     57 
     58   Status = EfiLibInstallDriverBindingComponentName2 (
     59              ImageHandle,
     60              SystemTable,
     61              &gConPlatformTextInDriverBinding,
     62              ImageHandle,
     63              &gConPlatformComponentName,
     64              &gConPlatformComponentName2
     65              );
     66   ASSERT_EFI_ERROR (Status);
     67 
     68   Status = EfiLibInstallDriverBindingComponentName2 (
     69              ImageHandle,
     70              SystemTable,
     71              &gConPlatformTextOutDriverBinding,
     72              NULL,
     73              &gConPlatformComponentName,
     74              &gConPlatformComponentName2
     75              );
     76   ASSERT_EFI_ERROR (Status);
     77 
     78   return EFI_SUCCESS;
     79 }
     80 
     81 
     82 /**
     83   Test to see if EFI_SIMPLE_TEXT_INPUT_PROTOCOL is supported on ControllerHandle.
     84 
     85   @param  This                Protocol instance pointer.
     86   @param  ControllerHandle    Handle of device to test.
     87   @param  RemainingDevicePath Optional parameter use to pick a specific child
     88                               device to start.
     89 
     90   @retval EFI_SUCCESS         This driver supports this device.
     91   @retval other               This driver does not support this device.
     92 
     93 **/
     94 EFI_STATUS
     95 EFIAPI
     96 ConPlatformTextInDriverBindingSupported (
     97   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
     98   IN  EFI_HANDLE                   ControllerHandle,
     99   IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath  OPTIONAL
    100   )
    101 {
    102   return ConPlatformDriverBindingSupported (
    103            This,
    104            ControllerHandle,
    105            &gEfiSimpleTextInProtocolGuid
    106            );
    107 }
    108 
    109 
    110 /**
    111   Test to see if EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL is supported on ControllerHandle.
    112 
    113   @param  This                Protocol instance pointer.
    114   @param  ControllerHandle    Handle of device to test.
    115   @param  RemainingDevicePath Optional parameter use to pick a specific child
    116                               device to start.
    117 
    118   @retval EFI_SUCCESS         This driver supports this device.
    119   @retval other               This driver does not support this device.
    120 
    121 **/
    122 EFI_STATUS
    123 EFIAPI
    124 ConPlatformTextOutDriverBindingSupported (
    125   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
    126   IN  EFI_HANDLE                   ControllerHandle,
    127   IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath  OPTIONAL
    128   )
    129 {
    130   return ConPlatformDriverBindingSupported (
    131            This,
    132            ControllerHandle,
    133            &gEfiSimpleTextOutProtocolGuid
    134            );
    135 }
    136 
    137 
    138 /**
    139   Test to see if the specified protocol is supported on ControllerHandle.
    140 
    141   @param  This                Protocol instance pointer.
    142   @param  ControllerHandle    Handle of device to test.
    143   @param  ProtocolGuid        The specfic protocol.
    144 
    145   @retval EFI_SUCCESS         This driver supports this device.
    146   @retval other               This driver does not support this device.
    147 
    148 **/
    149 EFI_STATUS
    150 ConPlatformDriverBindingSupported (
    151   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
    152   IN  EFI_HANDLE                   ControllerHandle,
    153   IN  EFI_GUID                     *ProtocolGuid
    154   )
    155 {
    156   EFI_STATUS  Status;
    157   VOID        *Interface;
    158 
    159   //
    160   // Test to see if this is a physical device by checking if
    161   // it has a Device Path Protocol.
    162   //
    163   Status = gBS->OpenProtocol (
    164                   ControllerHandle,
    165                   &gEfiDevicePathProtocolGuid,
    166                   NULL,
    167                   This->DriverBindingHandle,
    168                   ControllerHandle,
    169                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    170                   );
    171   if (EFI_ERROR (Status)) {
    172     return Status;
    173   }
    174   //
    175   // Test to see if this device supports the specified Protocol.
    176   //
    177   Status = gBS->OpenProtocol (
    178                   ControllerHandle,
    179                   ProtocolGuid,
    180                   (VOID **) &Interface,
    181                   This->DriverBindingHandle,
    182                   ControllerHandle,
    183                   EFI_OPEN_PROTOCOL_BY_DRIVER
    184                   );
    185   if (EFI_ERROR (Status)) {
    186     return Status;
    187   }
    188 
    189   gBS->CloseProtocol (
    190          ControllerHandle,
    191          ProtocolGuid,
    192          This->DriverBindingHandle,
    193          ControllerHandle
    194          );
    195 
    196   return EFI_SUCCESS;
    197 }
    198 
    199 /**
    200   Start this driver on the device for console input.
    201 
    202   Start this driver on ControllerHandle by opening Simple Text Input Protocol,
    203   reading Device Path, and installing Console In Devcice GUID on ControllerHandle.
    204 
    205   If this devcie is not one hot-plug devce, append its device path into the
    206   console environment variables ConInDev.
    207 
    208   @param  This                 Protocol instance pointer.
    209   @param  ControllerHandle     Handle of device to bind driver to
    210   @param  RemainingDevicePath  Optional parameter use to pick a specific child
    211                                device to start.
    212 
    213   @retval EFI_SUCCESS          This driver is added to ControllerHandle
    214   @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle
    215   @retval other                This driver does not support this device.
    216 
    217 **/
    218 EFI_STATUS
    219 EFIAPI
    220 ConPlatformTextInDriverBindingStart (
    221   IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
    222   IN  EFI_HANDLE                    ControllerHandle,
    223   IN  EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath
    224   )
    225 {
    226   EFI_STATUS                     Status;
    227   EFI_DEVICE_PATH_PROTOCOL       *DevicePath;
    228   EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn;
    229   BOOLEAN                        IsInConInVariable;
    230 
    231   //
    232   // Get the Device Path Protocol so the environment variables can be updated
    233   //
    234   Status = gBS->OpenProtocol (
    235                   ControllerHandle,
    236                   &gEfiDevicePathProtocolGuid,
    237                   (VOID **) &DevicePath,
    238                   This->DriverBindingHandle,
    239                   ControllerHandle,
    240                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    241                   );
    242   if (EFI_ERROR (Status)) {
    243     return Status;
    244   }
    245   //
    246   // Open the Simple Text Input Protocol BY_DRIVER
    247   //
    248   Status = gBS->OpenProtocol (
    249                   ControllerHandle,
    250                   &gEfiSimpleTextInProtocolGuid,
    251                   (VOID **) &TextIn,
    252                   This->DriverBindingHandle,
    253                   ControllerHandle,
    254                   EFI_OPEN_PROTOCOL_BY_DRIVER
    255                   );
    256   if (EFI_ERROR (Status)) {
    257     return Status;
    258   }
    259   //
    260   // Check if the device path is in ConIn Variable
    261   //
    262   IsInConInVariable = FALSE;
    263   Status = ConPlatformUpdateDeviceVariable (
    264              L"ConIn",
    265              DevicePath,
    266              Check
    267              );
    268   if (!EFI_ERROR (Status)) {
    269     IsInConInVariable = TRUE;
    270   }
    271 
    272   //
    273   // Check the device path, if it is a hot plug device,
    274   // do not put the device path into ConInDev, and install
    275   // gEfiConsoleInDeviceGuid to the device handle directly.
    276   // The policy is, make hot plug device plug in and play immediately.
    277   //
    278   if (IsHotPlugDevice (DevicePath)) {
    279     gBS->InstallMultipleProtocolInterfaces (
    280            &ControllerHandle,
    281            &gEfiConsoleInDeviceGuid,
    282            NULL,
    283            NULL
    284            );
    285     //
    286     // Append the device path to ConInDev only if it is in ConIn variable.
    287     //
    288     if (IsInConInVariable) {
    289       ConPlatformUpdateDeviceVariable (
    290         L"ConInDev",
    291         DevicePath,
    292         Append
    293         );
    294     }
    295   } else {
    296     //
    297     // If it is not a hot-plug device, append the device path to the
    298     // ConInDev environment variable
    299     //
    300     ConPlatformUpdateDeviceVariable (
    301       L"ConInDev",
    302       DevicePath,
    303       Append
    304       );
    305 
    306     //
    307     // If the device path is an instance in the ConIn environment variable,
    308     // then install EfiConsoleInDeviceGuid onto ControllerHandle
    309     //
    310     if (IsInConInVariable) {
    311       gBS->InstallMultipleProtocolInterfaces (
    312              &ControllerHandle,
    313              &gEfiConsoleInDeviceGuid,
    314              NULL,
    315              NULL
    316              );
    317     } else {
    318       gBS->CloseProtocol (
    319              ControllerHandle,
    320              &gEfiSimpleTextInProtocolGuid,
    321              This->DriverBindingHandle,
    322              ControllerHandle
    323              );
    324     }
    325   }
    326 
    327   return EFI_SUCCESS;
    328 }
    329 
    330 /**
    331   Start this driver on the device for console output and standard error output.
    332 
    333   Start this driver on ControllerHandle by opening Simple Text Output Protocol,
    334   reading Device Path, and installing Console Out Devcic GUID, Standard Error
    335   Device GUID on ControllerHandle.
    336 
    337   If this devcie is not one hot-plug devce, append its device path into the
    338   console environment variables ConOutDev, ErrOutDev.
    339 
    340   @param  This                 Protocol instance pointer.
    341   @param  ControllerHandle     Handle of device to bind driver to
    342   @param  RemainingDevicePath  Optional parameter use to pick a specific child
    343                                device to start.
    344 
    345   @retval EFI_SUCCESS          This driver is added to ControllerHandle
    346   @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle
    347   @retval other                This driver does not support this device
    348 
    349 **/
    350 EFI_STATUS
    351 EFIAPI
    352 ConPlatformTextOutDriverBindingStart (
    353   IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
    354   IN  EFI_HANDLE                    ControllerHandle,
    355   IN  EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath
    356   )
    357 {
    358   EFI_STATUS                       Status;
    359   EFI_DEVICE_PATH_PROTOCOL         *DevicePath;
    360   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *TextOut;
    361   BOOLEAN                          NeedClose;
    362   BOOLEAN                          IsInConOutVariable;
    363   BOOLEAN                          IsInErrOutVariable;
    364 
    365   NeedClose = TRUE;
    366 
    367   //
    368   // Get the Device Path Protocol so the environment variables can be updated
    369   //
    370   Status = gBS->OpenProtocol (
    371                   ControllerHandle,
    372                   &gEfiDevicePathProtocolGuid,
    373                   (VOID **) &DevicePath,
    374                   This->DriverBindingHandle,
    375                   ControllerHandle,
    376                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    377                   );
    378   if (EFI_ERROR (Status)) {
    379     return Status;
    380   }
    381   //
    382   // Open the Simple Text Output Protocol BY_DRIVER
    383   //
    384   Status = gBS->OpenProtocol (
    385                   ControllerHandle,
    386                   &gEfiSimpleTextOutProtocolGuid,
    387                   (VOID **) &TextOut,
    388                   This->DriverBindingHandle,
    389                   ControllerHandle,
    390                   EFI_OPEN_PROTOCOL_BY_DRIVER
    391                   );
    392   if (EFI_ERROR (Status)) {
    393     return Status;
    394   }
    395   //
    396   // Check if the device path is in ConOut & ErrOut Variable
    397   //
    398   IsInConOutVariable = FALSE;
    399   Status = ConPlatformUpdateDeviceVariable (
    400              L"ConOut",
    401              DevicePath,
    402              Check
    403              );
    404   if (!EFI_ERROR (Status)) {
    405     IsInConOutVariable = TRUE;
    406   }
    407 
    408   IsInErrOutVariable = FALSE;
    409   Status = ConPlatformUpdateDeviceVariable (
    410              L"ErrOut",
    411              DevicePath,
    412              Check
    413              );
    414   if (!EFI_ERROR (Status)) {
    415     IsInErrOutVariable = TRUE;
    416   }
    417 
    418   //
    419   // Check the device path, if it is a hot plug device,
    420   // do not put the device path into ConOutDev and ErrOutDev,
    421   // and install gEfiConsoleOutDeviceGuid to the device handle directly.
    422   // The policy is, make hot plug device plug in and play immediately.
    423   //
    424   if (IsHotPlugDevice (DevicePath)) {
    425     gBS->InstallMultipleProtocolInterfaces (
    426            &ControllerHandle,
    427            &gEfiConsoleOutDeviceGuid,
    428            NULL,
    429            NULL
    430            );
    431     //
    432     // Append the device path to ConOutDev only if it is in ConOut variable.
    433     //
    434     if (IsInConOutVariable) {
    435       ConPlatformUpdateDeviceVariable (
    436         L"ConOutDev",
    437         DevicePath,
    438         Append
    439         );
    440     }
    441     //
    442     // Append the device path to ErrOutDev only if it is in ErrOut variable.
    443     //
    444     if (IsInErrOutVariable) {
    445       ConPlatformUpdateDeviceVariable (
    446         L"ErrOutDev",
    447         DevicePath,
    448         Append
    449         );
    450     }
    451   } else {
    452     //
    453     // If it is not a hot-plug device, append the device path to
    454     // the ConOutDev and ErrOutDev environment variable.
    455     // For GOP device path, append the sibling device path as well.
    456     //
    457     if (!ConPlatformUpdateGopCandidate (DevicePath)) {
    458       ConPlatformUpdateDeviceVariable (
    459         L"ConOutDev",
    460         DevicePath,
    461         Append
    462         );
    463       //
    464       // Then append the device path to the ErrOutDev environment variable
    465       //
    466       ConPlatformUpdateDeviceVariable (
    467         L"ErrOutDev",
    468         DevicePath,
    469         Append
    470         );
    471     }
    472 
    473     //
    474     // If the device path is an instance in the ConOut environment variable,
    475     // then install EfiConsoleOutDeviceGuid onto ControllerHandle
    476     //
    477     if (IsInConOutVariable) {
    478       NeedClose = FALSE;
    479       Status = gBS->InstallMultipleProtocolInterfaces (
    480                       &ControllerHandle,
    481                       &gEfiConsoleOutDeviceGuid,
    482                       NULL,
    483                       NULL
    484                       );
    485     }
    486     //
    487     // If the device path is an instance in the ErrOut environment variable,
    488     // then install EfiStandardErrorDeviceGuid onto ControllerHandle
    489     //
    490     if (IsInErrOutVariable) {
    491       NeedClose = FALSE;
    492       gBS->InstallMultipleProtocolInterfaces (
    493              &ControllerHandle,
    494              &gEfiStandardErrorDeviceGuid,
    495              NULL,
    496              NULL
    497              );
    498     }
    499 
    500     if (NeedClose) {
    501       gBS->CloseProtocol (
    502              ControllerHandle,
    503              &gEfiSimpleTextOutProtocolGuid,
    504              This->DriverBindingHandle,
    505              ControllerHandle
    506              );
    507     }
    508   }
    509 
    510   return EFI_SUCCESS;
    511 }
    512 
    513 /**
    514   Stop this driver on ControllerHandle by removing Console In Devcice GUID
    515   and closing the Simple Text Input protocol on ControllerHandle.
    516 
    517   @param  This              Protocol instance pointer.
    518   @param  ControllerHandle  Handle of device to stop driver on
    519   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
    520                             children is zero stop the entire bus driver.
    521   @param  ChildHandleBuffer List of Child Handles to Stop.
    522 
    523   @retval EFI_SUCCESS       This driver is removed ControllerHandle
    524   @retval other             This driver was not removed from this device
    525 
    526 **/
    527 EFI_STATUS
    528 EFIAPI
    529 ConPlatformTextInDriverBindingStop (
    530   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
    531   IN  EFI_HANDLE                   ControllerHandle,
    532   IN  UINTN                        NumberOfChildren,
    533   IN  EFI_HANDLE                   *ChildHandleBuffer
    534   )
    535 {
    536   EFI_STATUS                Status;
    537   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
    538 
    539   //
    540   // Get the Device Path Protocol firstly
    541   //
    542   Status = gBS->OpenProtocol (
    543                   ControllerHandle,
    544                   &gEfiDevicePathProtocolGuid,
    545                   (VOID **) &DevicePath,
    546                   This->DriverBindingHandle,
    547                   ControllerHandle,
    548                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    549                   );
    550   //
    551   // If there is device path on ControllerHandle
    552   //
    553   if (!EFI_ERROR (Status)) {
    554     //
    555     // Remove DevicePath from ConInDev if exists.
    556     //
    557     ConPlatformUpdateDeviceVariable (
    558       L"ConInDev",
    559       DevicePath,
    560       Delete
    561       );
    562   }
    563 
    564   //
    565   // Uninstall the Console Device GUIDs from Controller Handle
    566   //
    567   ConPlatformUnInstallProtocol (
    568     This,
    569     ControllerHandle,
    570     &gEfiConsoleInDeviceGuid
    571     );
    572 
    573   //
    574   // Close the Simple Text Input Protocol
    575   //
    576   gBS->CloseProtocol (
    577          ControllerHandle,
    578          &gEfiSimpleTextInProtocolGuid,
    579          This->DriverBindingHandle,
    580          ControllerHandle
    581          );
    582 
    583   return EFI_SUCCESS;
    584 }
    585 
    586 
    587 /**
    588   Stop this driver on ControllerHandle by removing Console Out Devcice GUID
    589   and closing the Simple Text Output protocol on ControllerHandle.
    590 
    591   @param  This              Protocol instance pointer.
    592   @param  ControllerHandle  Handle of device to stop driver on
    593   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
    594                             children is zero stop the entire bus driver.
    595   @param  ChildHandleBuffer List of Child Handles to Stop.
    596 
    597   @retval EFI_SUCCESS       This driver is removed ControllerHandle
    598   @retval other             This driver was not removed from this device
    599 
    600 **/
    601 EFI_STATUS
    602 EFIAPI
    603 ConPlatformTextOutDriverBindingStop (
    604   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
    605   IN  EFI_HANDLE                   ControllerHandle,
    606   IN  UINTN                        NumberOfChildren,
    607   IN  EFI_HANDLE                   *ChildHandleBuffer
    608   )
    609 {
    610   EFI_STATUS                Status;
    611   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
    612 
    613   //
    614   // Get the Device Path Protocol firstly
    615   //
    616   Status = gBS->OpenProtocol (
    617                   ControllerHandle,
    618                   &gEfiDevicePathProtocolGuid,
    619                   (VOID **) &DevicePath,
    620                   This->DriverBindingHandle,
    621                   ControllerHandle,
    622                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    623                   );
    624   if (!EFI_ERROR (Status)) {
    625     //
    626     // Remove DevicePath from ConOutDev and ErrOutDev if exists.
    627     //
    628     ConPlatformUpdateDeviceVariable (
    629       L"ConOutDev",
    630       DevicePath,
    631       Delete
    632       );
    633     ConPlatformUpdateDeviceVariable (
    634       L"ErrOutDev",
    635       DevicePath,
    636       Delete
    637       );
    638   }
    639 
    640   //
    641   // Uninstall the Console Device GUIDs from Controller Handle
    642   //
    643   ConPlatformUnInstallProtocol (
    644     This,
    645     ControllerHandle,
    646     &gEfiConsoleOutDeviceGuid
    647     );
    648 
    649   ConPlatformUnInstallProtocol (
    650     This,
    651     ControllerHandle,
    652     &gEfiStandardErrorDeviceGuid
    653     );
    654 
    655   //
    656   // Close the Simple Text Output Protocol
    657   //
    658   gBS->CloseProtocol (
    659         ControllerHandle,
    660         &gEfiSimpleTextOutProtocolGuid,
    661         This->DriverBindingHandle,
    662         ControllerHandle
    663         );
    664 
    665   return EFI_SUCCESS;
    666 }
    667 
    668 
    669 /**
    670   Uninstall the specified protocol.
    671 
    672   @param This            Protocol instance pointer.
    673   @param Handle          Handle of device to uninstall protocol on.
    674   @param ProtocolGuid    The specified protocol need to be uninstalled.
    675 
    676 **/
    677 VOID
    678 ConPlatformUnInstallProtocol (
    679   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
    680   IN  EFI_HANDLE                   Handle,
    681   IN  EFI_GUID                     *ProtocolGuid
    682   )
    683 {
    684   EFI_STATUS  Status;
    685 
    686   Status = gBS->OpenProtocol (
    687                   Handle,
    688                   ProtocolGuid,
    689                   NULL,
    690                   This->DriverBindingHandle,
    691                   Handle,
    692                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    693                   );
    694 
    695   if (!EFI_ERROR (Status)) {
    696     gBS->UninstallMultipleProtocolInterfaces (
    697            Handle,
    698            ProtocolGuid,
    699            NULL,
    700            NULL
    701            );
    702   }
    703 
    704   return ;
    705 }
    706 
    707 /**
    708   Get the necessary size of buffer and read the variable.
    709 
    710   First get the necessary size of buffer. Then read the
    711   EFI variable (Name) and return a dynamically allocated
    712   buffer. On failure return NULL.
    713 
    714   @param  Name             String part of EFI variable name
    715 
    716   @return Dynamically allocated memory that contains a copy of the EFI variable.
    717           Caller is repsoncible freeing the buffer. Return NULL means Variable
    718           was not read.
    719 
    720 **/
    721 VOID *
    722 ConPlatformGetVariable (
    723   IN  CHAR16    *Name
    724   )
    725 {
    726   EFI_STATUS  Status;
    727   VOID        *Buffer;
    728   UINTN       BufferSize;
    729 
    730   BufferSize  = 0;
    731   Buffer      = NULL;
    732 
    733   //
    734   // Test to see if the variable exists.  If it doesn't, return NULL.
    735   //
    736   Status = gRT->GetVariable (
    737                   Name,
    738                   &gEfiGlobalVariableGuid,
    739                   NULL,
    740                   &BufferSize,
    741                   Buffer
    742                   );
    743 
    744   if (Status == EFI_BUFFER_TOO_SMALL) {
    745     //
    746     // Allocate the buffer to return
    747     //
    748     Buffer = AllocatePool (BufferSize);
    749     if (Buffer == NULL) {
    750       return NULL;
    751     }
    752     //
    753     // Read variable into the allocated buffer.
    754     //
    755     Status = gRT->GetVariable (
    756                     Name,
    757                     &gEfiGlobalVariableGuid,
    758                     NULL,
    759                     &BufferSize,
    760                     Buffer
    761                     );
    762     if (EFI_ERROR (Status)) {
    763       FreePool (Buffer);
    764       //
    765       // To make sure Buffer is NULL if any error occurs.
    766       //
    767       Buffer = NULL;
    768     }
    769   }
    770 
    771   return Buffer;
    772 }
    773 
    774 /**
    775   Function returns TRUE when the two input device paths point to the two
    776   GOP child handles that have the same parent.
    777 
    778   @param Left    A pointer to a device path data structure.
    779   @param Right   A pointer to a device path data structure.
    780 
    781   @retval TRUE  Left and Right share the same parent.
    782   @retval FALSE Left and Right don't share the same parent or either of them is not
    783                 a GOP device path.
    784 **/
    785 BOOLEAN
    786 IsGopSibling (
    787   IN EFI_DEVICE_PATH_PROTOCOL  *Left,
    788   IN EFI_DEVICE_PATH_PROTOCOL  *Right
    789   )
    790 {
    791   EFI_DEVICE_PATH_PROTOCOL  *NodeLeft;
    792   EFI_DEVICE_PATH_PROTOCOL  *NodeRight;
    793 
    794   for (NodeLeft = Left; !IsDevicePathEndType (NodeLeft); NodeLeft = NextDevicePathNode (NodeLeft)) {
    795     if ((DevicePathType (NodeLeft) == ACPI_DEVICE_PATH && DevicePathSubType (NodeLeft) == ACPI_ADR_DP) ||
    796         (DevicePathType (NodeLeft) == HARDWARE_DEVICE_PATH && DevicePathSubType (NodeLeft) == HW_CONTROLLER_DP &&
    797          DevicePathType (NextDevicePathNode (NodeLeft)) == ACPI_DEVICE_PATH && DevicePathSubType (NextDevicePathNode (NodeLeft)) == ACPI_ADR_DP)) {
    798       break;
    799     }
    800   }
    801 
    802   if (IsDevicePathEndType (NodeLeft)) {
    803     return FALSE;
    804   }
    805 
    806   for (NodeRight = Right; !IsDevicePathEndType (NodeRight); NodeRight = NextDevicePathNode (NodeRight)) {
    807     if ((DevicePathType (NodeRight) == ACPI_DEVICE_PATH && DevicePathSubType (NodeRight) == ACPI_ADR_DP) ||
    808         (DevicePathType (NodeRight) == HARDWARE_DEVICE_PATH && DevicePathSubType (NodeRight) == HW_CONTROLLER_DP &&
    809          DevicePathType (NextDevicePathNode (NodeRight)) == ACPI_DEVICE_PATH && DevicePathSubType (NextDevicePathNode (NodeRight)) == ACPI_ADR_DP)) {
    810       break;
    811     }
    812   }
    813 
    814   if (IsDevicePathEndType (NodeRight)) {
    815     return FALSE;
    816   }
    817 
    818   if (((UINTN) NodeLeft - (UINTN) Left) != ((UINTN) NodeRight - (UINTN) Right)) {
    819     return FALSE;
    820   }
    821 
    822   return (BOOLEAN) (CompareMem (Left, Right, (UINTN) NodeLeft - (UINTN) Left) == 0);
    823 }
    824 
    825 /**
    826   Function compares a device path data structure to that of all the nodes of a
    827   second device path instance.
    828 
    829   @param Multi           A pointer to a multi-instance device path data structure.
    830   @param Single          A pointer to a single-instance device path data structure.
    831   @param NewDevicePath   If Delete is TRUE, this parameter must not be null, and it
    832                          points to the remaining device path data structure.
    833                          (remaining device path = Multi - Single.)
    834   @param Delete          If TRUE, means removing Single from Multi.
    835                          If FALSE, the routine just check whether Single matches
    836                          with any instance in Multi.
    837 
    838   @retval EFI_SUCCESS           If the Single is contained within Multi.
    839   @retval EFI_NOT_FOUND         If the Single is not contained within Multi.
    840   @retval EFI_INVALID_PARAMETER Multi is NULL.
    841   @retval EFI_INVALID_PARAMETER Single is NULL.
    842   @retval EFI_INVALID_PARAMETER NewDevicePath is NULL when Delete is TRUE.
    843 
    844 **/
    845 EFI_STATUS
    846 ConPlatformMatchDevicePaths (
    847   IN  EFI_DEVICE_PATH_PROTOCOL  *Multi,
    848   IN  EFI_DEVICE_PATH_PROTOCOL  *Single,
    849   OUT EFI_DEVICE_PATH_PROTOCOL  **NewDevicePath OPTIONAL,
    850   IN  BOOLEAN                   Delete
    851   )
    852 {
    853   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
    854   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath1;
    855   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath2;
    856   EFI_DEVICE_PATH_PROTOCOL  *DevicePathInst;
    857   UINTN                     Size;
    858 
    859   //
    860   // The passed in DevicePath should not be NULL
    861   //
    862   if ((Multi == NULL) || (Single == NULL)) {
    863     return EFI_INVALID_PARAMETER;
    864   }
    865 
    866   //
    867   // If performing Delete operation, the NewDevicePath must not be NULL.
    868   //
    869   if (Delete) {
    870     if (NewDevicePath == NULL) {
    871       return EFI_INVALID_PARAMETER;
    872     }
    873   }
    874 
    875   TempDevicePath1 = NULL;
    876 
    877   DevicePath      = Multi;
    878   DevicePathInst  = GetNextDevicePathInstance (&DevicePath, &Size);
    879 
    880   //
    881   // Search for the match of 'Single' in 'Multi'
    882   //
    883   while (DevicePathInst != NULL) {
    884     if ((CompareMem (Single, DevicePathInst, Size) == 0) || IsGopSibling (Single, DevicePathInst)) {
    885       if (!Delete) {
    886         //
    887         // If Delete is FALSE, return EFI_SUCCESS if Single is found in Multi.
    888         //
    889         FreePool (DevicePathInst);
    890         return EFI_SUCCESS;
    891       }
    892     } else {
    893       if (Delete) {
    894         //
    895         // If the node of Multi does not match Single, then added it back to the result.
    896         // That is, the node matching Single will be dropped and deleted from result.
    897         //
    898         TempDevicePath2 = AppendDevicePathInstance (
    899                             TempDevicePath1,
    900                             DevicePathInst
    901                             );
    902         if (TempDevicePath1 != NULL) {
    903           FreePool (TempDevicePath1);
    904         }
    905         TempDevicePath1 = TempDevicePath2;
    906       }
    907     }
    908 
    909     FreePool (DevicePathInst);
    910     DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
    911   }
    912 
    913   if (Delete) {
    914     //
    915     // Return the new device path data structure with specified node deleted.
    916     //
    917     *NewDevicePath = TempDevicePath1;
    918     return EFI_SUCCESS;
    919   }
    920 
    921   return EFI_NOT_FOUND;
    922 }
    923 
    924 /**
    925   Update console environment variables.
    926 
    927   @param  VariableName    Console environment variables, ConOutDev, ConInDev
    928                           ErrOutDev, ConIn ,ConOut or ErrOut.
    929   @param  DevicePath      Console devcie's device path.
    930   @param  Operation       Variable operations, including APPEND, CHECK and DELETE.
    931 
    932   @retval EFI_SUCCESS           Variable operates successfully.
    933   @retval EFI_OUT_OF_RESOURCES  If variable cannot be appended.
    934   @retval other                 Variable updating failed.
    935 
    936 **/
    937 EFI_STATUS
    938 ConPlatformUpdateDeviceVariable (
    939   IN  CHAR16                    *VariableName,
    940   IN  EFI_DEVICE_PATH_PROTOCOL  *DevicePath,
    941   IN  CONPLATFORM_VAR_OPERATION Operation
    942   )
    943 {
    944   EFI_STATUS                Status;
    945   EFI_DEVICE_PATH_PROTOCOL  *VariableDevicePath;
    946   EFI_DEVICE_PATH_PROTOCOL  *NewVariableDevicePath;
    947 
    948   VariableDevicePath    = NULL;
    949   NewVariableDevicePath = NULL;
    950 
    951   //
    952   // Get Variable according to variable name.
    953   // The memory for Variable is allocated within ConPlatformGetVarible(),
    954   // it is the caller's responsibility to free the memory before return.
    955   //
    956   VariableDevicePath = ConPlatformGetVariable (VariableName);
    957 
    958   if (Operation != Delete) {
    959     //
    960     // Match specified DevicePath in Console Variable.
    961     //
    962     Status = ConPlatformMatchDevicePaths (
    963                VariableDevicePath,
    964                DevicePath,
    965                NULL,
    966                FALSE
    967                );
    968 
    969     if ((Operation == Check) || (!EFI_ERROR (Status))) {
    970       //
    971       // Branch here includes 2 cases:
    972       // 1. Operation is CHECK, simply return Status.
    973       // 2. Operation is APPEND, and device path already exists in variable, also return.
    974       //
    975       if (VariableDevicePath != NULL) {
    976         FreePool (VariableDevicePath);
    977       }
    978 
    979       return Status;
    980     }
    981     //
    982     // We reach here to append a device path that does not exist in variable.
    983     //
    984     Status = EFI_SUCCESS;
    985     NewVariableDevicePath = AppendDevicePathInstance (
    986                               VariableDevicePath,
    987                               DevicePath
    988                               );
    989     if (NewVariableDevicePath == NULL) {
    990       Status = EFI_OUT_OF_RESOURCES;
    991     }
    992 
    993   } else {
    994     //
    995     // We reach here to remove DevicePath from the environment variable that
    996     // is a multi-instance device path.
    997     //
    998     Status = ConPlatformMatchDevicePaths (
    999                VariableDevicePath,
   1000                DevicePath,
   1001                &NewVariableDevicePath,
   1002                TRUE
   1003                );
   1004   }
   1005 
   1006   if (VariableDevicePath != NULL) {
   1007     FreePool (VariableDevicePath);
   1008   }
   1009 
   1010   if (EFI_ERROR (Status)) {
   1011     return Status;
   1012   }
   1013 
   1014   if (NewVariableDevicePath != NULL) {
   1015     //
   1016     // Update Console Environment Variable.
   1017     //
   1018     Status = gRT->SetVariable (
   1019                     VariableName,
   1020                     &gEfiGlobalVariableGuid,
   1021                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
   1022                     GetDevicePathSize (NewVariableDevicePath),
   1023                     NewVariableDevicePath
   1024                     );
   1025 
   1026     FreePool (NewVariableDevicePath);
   1027   }
   1028 
   1029   return Status;
   1030 }
   1031 
   1032 /**
   1033   Check if the device supports hot-plug through its device path.
   1034 
   1035   This function could be updated to check more types of Hot Plug devices.
   1036   Currently, it checks USB and PCCard device.
   1037 
   1038   @param  DevicePath            Pointer to device's device path.
   1039 
   1040   @retval TRUE                  The devcie is a hot-plug device
   1041   @retval FALSE                 The devcie is not a hot-plug device.
   1042 
   1043 **/
   1044 BOOLEAN
   1045 IsHotPlugDevice (
   1046   IN  EFI_DEVICE_PATH_PROTOCOL    *DevicePath
   1047   )
   1048 {
   1049   EFI_DEVICE_PATH_PROTOCOL     *CheckDevicePath;
   1050 
   1051   CheckDevicePath = DevicePath;
   1052   while (!IsDevicePathEnd (CheckDevicePath)) {
   1053     //
   1054     // Check device whether is hot plug device or not throught Device Path
   1055     //
   1056     if ((DevicePathType (CheckDevicePath) == MESSAGING_DEVICE_PATH) &&
   1057         (DevicePathSubType (CheckDevicePath) == MSG_USB_DP ||
   1058          DevicePathSubType (CheckDevicePath) == MSG_USB_CLASS_DP ||
   1059          DevicePathSubType (CheckDevicePath) == MSG_USB_WWID_DP)) {
   1060       //
   1061       // If Device is USB device
   1062       //
   1063       return TRUE;
   1064     }
   1065     if ((DevicePathType (CheckDevicePath) == HARDWARE_DEVICE_PATH) &&
   1066         (DevicePathSubType (CheckDevicePath) == HW_PCCARD_DP)) {
   1067       //
   1068       // If Device is PCCard
   1069       //
   1070       return TRUE;
   1071     }
   1072 
   1073     CheckDevicePath = NextDevicePathNode (CheckDevicePath);
   1074   }
   1075 
   1076   return FALSE;
   1077 }
   1078 
   1079 /**
   1080   Update ConOutDev and ErrOutDev variables to add the device path of
   1081   GOP controller itself and the sibling controllers.
   1082 
   1083   @param  DevicePath            Pointer to device's device path.
   1084 
   1085   @retval TRUE                  The devcie is a GOP device.
   1086   @retval FALSE                 The devcie is not a GOP device.
   1087 
   1088 **/
   1089 BOOLEAN
   1090 ConPlatformUpdateGopCandidate (
   1091   IN  EFI_DEVICE_PATH_PROTOCOL    *DevicePath
   1092   )
   1093 {
   1094   EFI_STATUS                           Status;
   1095   EFI_HANDLE                           PciHandle;
   1096   EFI_HANDLE                           GopHandle;
   1097   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY  *OpenInfoBuffer;
   1098   UINTN                                EntryCount;
   1099   UINTN                                Index;
   1100   EFI_DEVICE_PATH_PROTOCOL             *ChildDevicePath;
   1101   EFI_DEVICE_PATH_PROTOCOL             *TempDevicePath;
   1102 
   1103   //
   1104   // Check whether it's a GOP device.
   1105   //
   1106   TempDevicePath = DevicePath;
   1107   Status = gBS->LocateDevicePath (&gEfiGraphicsOutputProtocolGuid, &TempDevicePath, &GopHandle);
   1108   if (EFI_ERROR (Status)) {
   1109     return FALSE;
   1110   }
   1111   //
   1112   // Get the parent PciIo handle in order to find all the children
   1113   //
   1114   Status = gBS->LocateDevicePath (&gEfiPciIoProtocolGuid, &DevicePath, &PciHandle);
   1115   if (EFI_ERROR (Status)) {
   1116     return FALSE;
   1117   }
   1118 
   1119   Status = gBS->OpenProtocolInformation (
   1120                   PciHandle,
   1121                   &gEfiPciIoProtocolGuid,
   1122                   &OpenInfoBuffer,
   1123                   &EntryCount
   1124                   );
   1125   if (EFI_ERROR (Status)) {
   1126     return FALSE;
   1127   }
   1128 
   1129   for (Index = 0; Index < EntryCount; Index++) {
   1130     //
   1131     // Query all the children created by the GOP driver
   1132     //
   1133     if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
   1134       Status = gBS->OpenProtocol (
   1135                       OpenInfoBuffer[Index].ControllerHandle,
   1136                       &gEfiDevicePathProtocolGuid,
   1137                       (VOID **) &ChildDevicePath,
   1138                       NULL,
   1139                       NULL,
   1140                       EFI_OPEN_PROTOCOL_GET_PROTOCOL
   1141                       );
   1142       if (!EFI_ERROR (Status)) {
   1143         //
   1144         // Append the device path to ConOutDev and ErrOutDev
   1145         //
   1146         ConPlatformUpdateDeviceVariable (L"ConOutDev", ChildDevicePath, Append);
   1147         ConPlatformUpdateDeviceVariable (L"ErrOutDev", ChildDevicePath, Append);
   1148       }
   1149     }
   1150   }
   1151   FreePool (OpenInfoBuffer);
   1152 
   1153   return TRUE;
   1154 }
   1155