summaryrefslogtreecommitdiff
path: root/EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.c
diff options
context:
space:
mode:
Diffstat (limited to 'EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.c')
-rw-r--r--EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.c811
1 files changed, 811 insertions, 0 deletions
diff --git a/EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.c b/EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.c
new file mode 100644
index 0000000000..4b7d2796d0
--- /dev/null
+++ b/EdkNt32Pkg/Dxe/ConPlatform/ConPlatform.c
@@ -0,0 +1,811 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ ConPlatform.c
+
+Abstract:
+
+--*/
+
+#include "ConPlatform.h"
+
+EFI_DRIVER_BINDING_PROTOCOL gConPlatformTextInDriverBinding = {
+ ConPlatformTextInDriverBindingSupported,
+ ConPlatformTextInDriverBindingStart,
+ ConPlatformDriverBindingStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+EFI_DRIVER_BINDING_PROTOCOL gConPlatformTextOutDriverBinding = {
+ ConPlatformTextOutDriverBindingSupported,
+ ConPlatformTextOutDriverBindingStart,
+ ConPlatformDriverBindingStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+STATIC
+EFI_STATUS
+EFIAPI
+ConPlatformTextInDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+/*++
+
+Routine Description:
+ Supported
+
+Arguments:
+ (Standard DriverBinding Protocol Supported() function)
+
+Returns:
+
+ None
+
+--*/
+{
+ return ConPlatformDriverBindingSupported (
+ This,
+ ControllerHandle,
+ RemainingDevicePath,
+ &gEfiSimpleTextInProtocolGuid
+ );
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+ConPlatformTextOutDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+/*++
+
+Routine Description:
+ Supported
+
+Arguments:
+ (Standard DriverBinding Protocol Supported() function)
+
+Returns:
+
+ None
+
+--*/
+{
+ return ConPlatformDriverBindingSupported (
+ This,
+ ControllerHandle,
+ RemainingDevicePath,
+ &gEfiSimpleTextOutProtocolGuid
+ );
+}
+
+EFI_STATUS
+ConPlatformDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,
+ IN EFI_GUID *ProtocolGuid
+ )
+/*++
+
+Routine Description:
+ Supported
+
+Arguments:
+ (Standard DriverBinding Protocol Supported() function)
+
+Returns:
+
+ None
+
+--*/
+{
+ EFI_STATUS Status;
+ VOID *Interface;
+
+ //
+ // Test to see if this is a physical device by checking to see if
+ // it has a Device Path Protocol
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Test to see if this device supports the Simple Text Output Protocol
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ ProtocolGuid,
+ (VOID **) &Interface,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (
+ ControllerHandle,
+ ProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+ConPlatformTextInDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+ (Standard DriverBinding Protocol Start() function)
+
+Returns:
+
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_SIMPLE_TEXT_IN_PROTOCOL *TextIn;
+
+ //
+ // Get the Device Path Protocol so the environment variables can be updated
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Open the Simple Input Protocol BY_DRIVER
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiSimpleTextInProtocolGuid,
+ (VOID **) &TextIn,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the device handle, if it is a hot plug device,
+ // do not put the device path into ConInDev, and install
+ // gEfiConsoleInDeviceGuid to the device handle directly.
+ // The policy is, make hot plug device plug in and play immediately.
+ //
+ if (IsHotPlugDevice (This->DriverBindingHandle, ControllerHandle)) {
+ gBS->InstallMultipleProtocolInterfaces (
+ &ControllerHandle,
+ &gEfiConsoleInDeviceGuid,
+ NULL,
+ NULL
+ );
+ } else {
+ //
+ // Append the device path to the ConInDev environment variable
+ //
+ ConPlatformUpdateDeviceVariable (
+ VarConsoleInpDev,
+ DevicePath,
+ APPEND
+ );
+
+ //
+ // If the device path is an instance in the ConIn environment variable,
+ // then install EfiConsoleInDeviceGuid onto ControllerHandle
+ //
+ Status = ConPlatformUpdateDeviceVariable (
+ VarConsoleInp,
+ DevicePath,
+ CHECK
+ );
+
+ if (!EFI_ERROR (Status)) {
+ gBS->InstallMultipleProtocolInterfaces (
+ &ControllerHandle,
+ &gEfiConsoleInDeviceGuid,
+ NULL,
+ NULL
+ );
+ } else {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiSimpleTextInProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+ConPlatformTextOutDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+ (Standard DriverBinding Protocol Start() function)
+
+Returns:
+
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_SIMPLE_TEXT_OUT_PROTOCOL *TextOut;
+
+ BOOLEAN NeedClose;
+
+ NeedClose = TRUE;
+
+ //
+ // Get the Device Path Protocol so the environment variables can be updated
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Open the Simple Text Output Protocol BY_DRIVER
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiSimpleTextOutProtocolGuid,
+ (VOID **) &TextOut,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the device handle, if it is a hot plug device,
+ // do not put the device path into ConOutDev and StdErrDev,
+ // and install gEfiConsoleOutDeviceGuid to the device handle directly.
+ // The policy is, make hot plug device plug in and play immediately.
+ //
+ if (IsHotPlugDevice (This->DriverBindingHandle, ControllerHandle)) {
+ gBS->InstallMultipleProtocolInterfaces (
+ &ControllerHandle,
+ &gEfiConsoleOutDeviceGuid,
+ NULL,
+ NULL
+ );
+ } else {
+ //
+ // Append the device path to the ConOutDev environment variable
+ //
+ ConPlatformUpdateDeviceVariable (
+ VarConsoleOutDev,
+ DevicePath,
+ APPEND
+ );
+ //
+ // Append the device path to the StdErrDev environment variable
+ //
+ ConPlatformUpdateDeviceVariable (
+ VarErrorOutDev,
+ DevicePath,
+ APPEND
+ );
+
+ //
+ // If the device path is an instance in the ConOut environment variable,
+ // then install EfiConsoleOutDeviceGuid onto ControllerHandle
+ //
+ Status = ConPlatformUpdateDeviceVariable (
+ VarConsoleOut,
+ DevicePath,
+ CHECK
+ );
+ if (!EFI_ERROR (Status)) {
+ NeedClose = FALSE;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ControllerHandle,
+ &gEfiConsoleOutDeviceGuid,
+ NULL,
+ NULL
+ );
+ }
+ //
+ // If the device path is an instance in the StdErr environment variable,
+ // then install EfiStandardErrorDeviceGuid onto ControllerHandle
+ //
+ Status = ConPlatformUpdateDeviceVariable (
+ VarErrorOut,
+ DevicePath,
+ CHECK
+ );
+ if (!EFI_ERROR (Status)) {
+ NeedClose = FALSE;
+ gBS->InstallMultipleProtocolInterfaces (
+ &ControllerHandle,
+ &gEfiStandardErrorDeviceGuid,
+ NULL,
+ NULL
+ );
+ }
+
+ if (NeedClose) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiSimpleTextOutProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+ConPlatformDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+ (Standard DriverBinding Protocol Stop() function)
+
+Returns:
+
+ None
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ //
+ // hot plug device is not included into the console associated variables,
+ // so no need to check variable for those hot plug devices.
+ //
+ if (!IsHotPlugDevice (This->DriverBindingHandle, ControllerHandle)) {
+ //
+ // Get the Device Path Protocol so the environment variables can be updated
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Remove DevicePath from ConInDev, ConOutDev, and StdErrDev
+ //
+ ConPlatformUpdateDeviceVariable (
+ VarConsoleInpDev,
+ DevicePath,
+ DELETE
+ );
+ ConPlatformUpdateDeviceVariable (
+ VarConsoleOutDev,
+ DevicePath,
+ DELETE
+ );
+ ConPlatformUpdateDeviceVariable (
+ VarErrorOutDev,
+ DevicePath,
+ DELETE
+ );
+ }
+ }
+ //
+ // Uninstall the Console Device GUIDs from Controller Handle
+ //
+ ConPlatformUnInstallProtocol (
+ This,
+ ControllerHandle,
+ &gEfiConsoleInDeviceGuid
+ );
+
+ ConPlatformUnInstallProtocol (
+ This,
+ ControllerHandle,
+ &gEfiConsoleOutDeviceGuid
+ );
+
+ ConPlatformUnInstallProtocol (
+ This,
+ ControllerHandle,
+ &gEfiStandardErrorDeviceGuid
+ );
+
+ //
+ // Close the Simple Input and Simple Text Output Protocols
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiSimpleTextInProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiSimpleTextOutProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ return EFI_SUCCESS;
+}
+
+VOID
+ConPlatformUnInstallProtocol (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_GUID *ProtocolGuid
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->OpenProtocol (
+ Handle,
+ ProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ Handle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ Handle,
+ ProtocolGuid,
+ NULL,
+ NULL
+ );
+ }
+
+ return ;
+}
+
+VOID *
+ConPlatformGetVariable (
+ IN CHAR16 *Name
+ )
+/*++
+
+Routine Description:
+ Read the EFI variable (Name) and return a dynamically allocated
+ buffer, and the size of the buffer. On failure return NULL.
+
+Arguments:
+ Name - String part of EFI variable name
+
+Returns:
+ Dynamically allocated memory that contains a copy of the EFI variable.
+ Caller is repsoncible freeing the buffer.
+
+ NULL - Variable was not read
+
+--*/
+{
+ EFI_STATUS Status;
+ VOID *Buffer;
+ UINTN BufferSize;
+
+ BufferSize = 0;
+ Buffer = NULL;
+
+ //
+ // Test to see if the variable exists. If it doesn't reuturn NULL
+ //
+ Status = gRT->GetVariable (
+ Name,
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &BufferSize,
+ Buffer
+ );
+
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ //
+ // Allocate the buffer to return
+ //
+ Status = gBS->AllocatePool (EfiBootServicesData, BufferSize, &Buffer);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ //
+ // Read variable into the allocated buffer.
+ //
+ Status = gRT->GetVariable (
+ Name,
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &BufferSize,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (Buffer);
+ Buffer = NULL;
+ }
+ }
+
+ return Buffer;
+}
+
+EFI_STATUS
+ConPlatformMatchDevicePaths (
+ IN EFI_DEVICE_PATH_PROTOCOL * Multi,
+ IN EFI_DEVICE_PATH_PROTOCOL * Single,
+ IN EFI_DEVICE_PATH_PROTOCOL **NewDevicePath OPTIONAL,
+ IN BOOLEAN Delete
+ )
+/*++
+
+Routine Description:
+ Function compares a device path data structure to that of all the nodes of a
+ second device path instance.
+
+Arguments:
+ Multi - A pointer to a multi-instance device path data structure.
+
+ Single - A pointer to a single-instance device path data structure.
+
+ NewDevicePath - If Delete is TRUE, this parameter must not be null, and it
+ points to the remaining device path data structure.
+ (remaining device path = Multi - Single.)
+
+ Delete - If TRUE, means removing Single from Multi.
+ If FALSE, the routine just check whether Single matches
+ with any instance in Multi.
+
+Returns:
+
+ The function returns EFI_SUCCESS if the Single is contained within Multi.
+ Otherwise, EFI_NOT_FOUND is returned.
+
+--*/
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath1;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath2;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
+ UINTN Size;
+
+ //
+ // The passed in DevicePath should not be NULL
+ //
+ if ((!Multi) || (!Single)) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // if performing Delete operation, the NewDevicePath must not be NULL.
+ //
+ TempDevicePath1 = NULL;
+
+ DevicePath = Multi;
+ DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
+
+ //
+ // search for the match of 'Single' in 'Multi'
+ //
+ while (DevicePathInst) {
+ if (CompareMem (Single, DevicePathInst, Size) == 0) {
+ if (!Delete) {
+ gBS->FreePool (DevicePathInst);
+ return EFI_SUCCESS;
+ }
+ } else {
+ if (Delete) {
+ TempDevicePath2 = AppendDevicePathInstance (
+ TempDevicePath1,
+ DevicePathInst
+ );
+ gBS->FreePool (TempDevicePath1);
+ TempDevicePath1 = TempDevicePath2;
+ }
+ }
+
+ gBS->FreePool (DevicePathInst);
+ DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
+ }
+
+ if (Delete) {
+ *NewDevicePath = TempDevicePath1;
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+EFI_STATUS
+ConPlatformUpdateDeviceVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN CONPLATFORM_VAR_OPERATION Operation
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+Returns:
+
+ None
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *VariableDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *NewVariableDevicePath;
+
+ VariableDevicePath = NULL;
+ NewVariableDevicePath = NULL;
+
+ //
+ // Get Variable according to variable name.
+ // The memory for Variable is allocated within ConPlatformGetVarible(),
+ // it is the caller's responsibility to free the memory before return.
+ //
+ VariableDevicePath = ConPlatformGetVariable (VariableName);
+
+ if (Operation != DELETE) {
+
+ Status = ConPlatformMatchDevicePaths (
+ VariableDevicePath,
+ DevicePath,
+ NULL,
+ FALSE
+ );
+
+ if ((Operation == CHECK) || (!EFI_ERROR (Status))) {
+ //
+ // The device path is already in the variable
+ //
+ gBS->FreePool (VariableDevicePath);
+
+ return Status;
+ }
+ //
+ // The device path is not in variable. Append DevicePath to the
+ // environment variable that is a multi-instance device path.
+ //
+ Status = EFI_SUCCESS;
+ NewVariableDevicePath = AppendDevicePathInstance (
+ VariableDevicePath,
+ DevicePath
+ );
+ if (NewVariableDevicePath == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ }
+
+ } else {
+ //
+ // Remove DevicePath from the environment variable that
+ // is a multi-instance device path.
+ //
+ Status = ConPlatformMatchDevicePaths (
+ VariableDevicePath,
+ DevicePath,
+ &NewVariableDevicePath,
+ TRUE
+ );
+ }
+
+ gBS->FreePool (VariableDevicePath);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gRT->SetVariable (
+ VariableName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ GetDevicePathSize (NewVariableDevicePath),
+ NewVariableDevicePath
+ );
+
+ gBS->FreePool (NewVariableDevicePath);
+
+ return Status;
+}
+
+BOOLEAN
+IsHotPlugDevice (
+ EFI_HANDLE DriverBindingHandle,
+ EFI_HANDLE ControllerHandle
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // HotPlugDeviceGuid indicates ControllerHandle stands for a hot plug device.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiHotPlugDeviceGuid,
+ NULL,
+ DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}