summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c')
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c1383
1 files changed, 1383 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
new file mode 100644
index 00000000..10d1210d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
@@ -0,0 +1,1383 @@
+/** @file
+ Produces Simple Text Input Protocol, Simple Text Input Extended Protocol and
+ Simple Text Output Protocol upon Serial IO Protocol.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "Terminal.h"
+
+//
+// Globals
+//
+EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding = {
+ TerminalDriverBindingSupported,
+ TerminalDriverBindingStart,
+ TerminalDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+
+EFI_GUID *mTerminalType[] = {
+ &gEfiPcAnsiGuid,
+ &gEfiVT100Guid,
+ &gEfiVT100PlusGuid,
+ &gEfiVTUTF8Guid,
+ &gEfiTtyTermGuid,
+ &gEdkiiLinuxTermGuid,
+ &gEdkiiXtermR6Guid,
+ &gEdkiiVT400Guid,
+ &gEdkiiSCOTermGuid
+};
+
+
+CHAR16 *mSerialConsoleNames[] = {
+ L"PC-ANSI Serial Console",
+ L"VT-100 Serial Console",
+ L"VT-100+ Serial Console",
+ L"VT-UTF8 Serial Console",
+ L"Tty Terminal Serial Console",
+ L"Linux Terminal Serial Console",
+ L"Xterm R6 Serial Console",
+ L"VT-400 Serial Console",
+ L"SCO Terminal Serial Console"
+};
+
+TERMINAL_DEV mTerminalDevTemplate = {
+ TERMINAL_DEV_SIGNATURE,
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ { // SimpleTextInput
+ TerminalConInReset,
+ TerminalConInReadKeyStroke,
+ NULL
+ },
+ { // SimpleTextOutput
+ TerminalConOutReset,
+ TerminalConOutOutputString,
+ TerminalConOutTestString,
+ TerminalConOutQueryMode,
+ TerminalConOutSetMode,
+ TerminalConOutSetAttribute,
+ TerminalConOutClearScreen,
+ TerminalConOutSetCursorPosition,
+ TerminalConOutEnableCursor,
+ NULL
+ },
+ { // SimpleTextOutputMode
+ 1, // MaxMode
+ 0, // Mode
+ EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK), // Attribute
+ 0, // CursorColumn
+ 0, // CursorRow
+ TRUE // CursorVisible
+ },
+ NULL, // TerminalConsoleModeData
+ 0, // SerialInTimeOut
+
+ NULL, // RawFifo
+ NULL, // UnicodeFiFo
+ NULL, // EfiKeyFiFo
+ NULL, // EfiKeyFiFoForNotify
+
+ NULL, // ControllerNameTable
+ NULL, // TimerEvent
+ NULL, // TwoSecondTimeOut
+ INPUT_STATE_DEFAULT,
+ RESET_STATE_DEFAULT,
+ {
+ 0,
+ 0,
+ 0
+ },
+ 0,
+ FALSE,
+ { // SimpleTextInputEx
+ TerminalConInResetEx,
+ TerminalConInReadKeyStrokeEx,
+ NULL,
+ TerminalConInSetState,
+ TerminalConInRegisterKeyNotify,
+ TerminalConInUnregisterKeyNotify,
+ },
+ { // NotifyList
+ NULL,
+ NULL,
+ },
+ NULL // KeyNotifyProcessEvent
+};
+
+TERMINAL_CONSOLE_MODE_DATA mTerminalConsoleModeData[] = {
+ {80, 25},
+ {80, 50},
+ {100, 31},
+ //
+ // New modes can be added here.
+ //
+};
+
+/**
+ Convert the GUID representation of terminal type to enum type.
+
+ @param Guid The GUID representation of terminal type.
+
+ @return The terminal type in enum type.
+**/
+TERMINAL_TYPE
+TerminalTypeFromGuid (
+ IN EFI_GUID *Guid
+)
+{
+ TERMINAL_TYPE Type;
+
+ for (Type = 0; Type < ARRAY_SIZE (mTerminalType); Type++) {
+ if (CompareGuid (Guid, mTerminalType[Type])) {
+ break;
+ }
+ }
+ return Type;
+}
+
+/**
+ Test to see if this driver supports Controller.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;
+ VENDOR_DEVICE_PATH *Node;
+
+ //
+ // If remaining device path is not NULL, then make sure it is a
+ // device path that describes a terminal communications protocol.
+ //
+ if (RemainingDevicePath != NULL) {
+ //
+ // Check if RemainingDevicePath is the End of Device Path Node,
+ // if yes, go on checking other conditions
+ //
+ if (!IsDevicePathEnd (RemainingDevicePath)) {
+ //
+ // If RemainingDevicePath isn't the End of Device Path Node,
+ // check its validation
+ //
+ Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;
+
+ if (Node->Header.Type != MESSAGING_DEVICE_PATH ||
+ Node->Header.SubType != MSG_VENDOR_DP ||
+ DevicePathNodeLength(&Node->Header) != sizeof(VENDOR_DEVICE_PATH)) {
+
+ return EFI_UNSUPPORTED;
+
+ }
+ //
+ // only supports PC ANSI, VT100, VT100+, VT-UTF8, TtyTerm
+ // Linux, XtermR6, VT400 and SCO terminal types
+ //
+ if (TerminalTypeFromGuid (&Node->Guid) == ARRAY_SIZE (mTerminalType)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+ }
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ // The Controller must support the Serial I/O Protocol.
+ // This driver is a bus driver with at most 1 child device, so it is
+ // ok for it to be already started.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ (VOID **) &SerialIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Open the EFI Device Path protocol needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Close protocol, don't use device path protocol in the Support() function
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+
+/**
+ Free notify functions list.
+
+ @param ListHead The list head
+
+ @retval EFI_SUCCESS Free the notify list successfully.
+ @retval EFI_INVALID_PARAMETER ListHead is NULL.
+
+**/
+EFI_STATUS
+TerminalFreeNotifyList (
+ IN OUT LIST_ENTRY *ListHead
+ )
+{
+ TERMINAL_CONSOLE_IN_EX_NOTIFY *NotifyNode;
+
+ if (ListHead == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ while (!IsListEmpty (ListHead)) {
+ NotifyNode = CR (
+ ListHead->ForwardLink,
+ TERMINAL_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ RemoveEntryList (ListHead->ForwardLink);
+ FreePool (NotifyNode);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize all the text modes which the terminal console supports.
+
+ It returns information for available text modes that the terminal can support.
+
+ @param[out] TextModeCount The total number of text modes that terminal console supports.
+
+ @return The buffer to the text modes column and row information.
+ Caller is responsible to free it when it's non-NULL.
+
+**/
+TERMINAL_CONSOLE_MODE_DATA *
+InitializeTerminalConsoleTextMode (
+ OUT INT32 *TextModeCount
+)
+{
+ TERMINAL_CONSOLE_MODE_DATA *TextModeData;
+
+ ASSERT (TextModeCount != NULL);
+
+ TextModeData = AllocateCopyPool (sizeof (mTerminalConsoleModeData), mTerminalConsoleModeData);
+ if (TextModeData == NULL) {
+ return NULL;
+ }
+ *TextModeCount = ARRAY_SIZE (mTerminalConsoleModeData);
+
+ DEBUG_CODE (
+ INT32 Index;
+ for (Index = 0; Index < *TextModeCount; Index++) {
+ DEBUG ((DEBUG_INFO, "Terminal - Mode %d, Column = %d, Row = %d\n",
+ Index, TextModeData[Index].Columns, TextModeData[Index].Rows));
+ }
+ );
+ return TextModeData;
+}
+
+/**
+ Stop the terminal state machine.
+
+ @param TerminalDevice The terminal device.
+**/
+VOID
+StopTerminalStateMachine (
+ TERMINAL_DEV *TerminalDevice
+ )
+{
+ EFI_TPL OriginalTpl;
+
+ OriginalTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ gBS->CloseEvent (TerminalDevice->TimerEvent);
+ gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);
+
+ gBS->RestoreTPL (OriginalTpl);
+}
+
+/**
+ Start the terminal state machine.
+
+ @param TerminalDevice The terminal device.
+**/
+VOID
+StartTerminalStateMachine (
+ TERMINAL_DEV *TerminalDevice
+ )
+{
+ EFI_STATUS Status;
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ TerminalConInTimerHandler,
+ TerminalDevice,
+ &TerminalDevice->TimerEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->SetTimer (
+ TerminalDevice->TimerEvent,
+ TimerPeriodic,
+ KEYBOARD_TIMER_INTERVAL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CreateEvent (
+ EVT_TIMER,
+ TPL_CALLBACK,
+ NULL,
+ NULL,
+ &TerminalDevice->TwoSecondTimeOut
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Initialize the controller name table.
+
+ @param TerminalType The terminal type.
+ @param ControllerNameTable The controller name table.
+
+ @retval EFI_SUCCESS The controller name table is initialized successfully.
+ @retval others Return status of AddUnicodeString2 ().
+**/
+EFI_STATUS
+InitializeControllerNameTable (
+ TERMINAL_TYPE TerminalType,
+ EFI_UNICODE_STRING_TABLE **ControllerNameTable
+)
+{
+ EFI_STATUS Status;
+ EFI_UNICODE_STRING_TABLE *Table;
+
+ ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));
+ Table = NULL;
+ Status = AddUnicodeString2 (
+ "eng",
+ gTerminalComponentName.SupportedLanguages,
+ &Table,
+ mSerialConsoleNames[TerminalType],
+ TRUE
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = AddUnicodeString2 (
+ "en",
+ gTerminalComponentName2.SupportedLanguages,
+ &Table,
+ mSerialConsoleNames[TerminalType],
+ FALSE
+ );
+ if (EFI_ERROR (Status)) {
+ FreeUnicodeStringTable (Table);
+ }
+ }
+ if (!EFI_ERROR (Status)) {
+ *ControllerNameTable = Table;
+ }
+ return Status;
+}
+
+/**
+ Start this driver on Controller by opening a Serial IO protocol,
+ reading Device Path, and creating a child handle with a Simple Text In,
+ Simple Text In Ex and Simple Text Out protocol, and device path protocol.
+ And store Console Device Environment Variables.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to bind driver to
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver is added to Controller.
+ @retval EFI_ALREADY_STARTED This driver is already running on Controller.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *Vendor;
+ EFI_HANDLE SerialIoHandle;
+ EFI_SERIAL_IO_MODE *Mode;
+ UINTN SerialInTimeOut;
+ TERMINAL_DEV *TerminalDevice;
+ UINT8 TerminalType;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
+ UINTN EntryCount;
+ UINTN Index;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextInput;
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+
+ //
+ // Get the Device Path Protocol to build the device path of the child device
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ ASSERT ((Status == EFI_SUCCESS) || (Status == EFI_ALREADY_STARTED));
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ return Status;
+ }
+
+ //
+ // Open the Serial I/O Protocol BY_DRIVER. It might already be started.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ (VOID **) &SerialIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ ASSERT ((Status == EFI_SUCCESS) || (Status == EFI_ALREADY_STARTED));
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ return Status;
+ }
+
+ if (!IsHotPlugDevice (ParentDevicePath)) {
+ //
+ // if the serial device is a hot plug device, do not update the
+ // ConInDev, ConOutDev, and StdErrDev variables.
+ //
+ TerminalUpdateConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME, ParentDevicePath);
+ TerminalUpdateConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
+ TerminalUpdateConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
+ }
+
+ //
+ // Do not create any child for END remaining device path.
+ //
+ if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) {
+ return EFI_SUCCESS;
+ }
+
+ if (Status == EFI_ALREADY_STARTED) {
+
+ if (RemainingDevicePath == NULL) {
+ //
+ // If RemainingDevicePath is NULL or is the End of Device Path Node
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // This driver can only produce one child per serial port.
+ // Change its terminal type as remaining device path requests.
+ //
+ Status = gBS->OpenProtocolInformation (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ &OpenInfoBuffer,
+ &EntryCount
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = EFI_NOT_FOUND;
+ for (Index = 0; Index < EntryCount; Index++) {
+ if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
+ Status = gBS->OpenProtocol (
+ OpenInfoBuffer[Index].ControllerHandle,
+ &gEfiSimpleTextInProtocolGuid,
+ (VOID **) &SimpleTextInput,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (SimpleTextInput);
+ TerminalType = TerminalTypeFromGuid (&((VENDOR_DEVICE_PATH *) RemainingDevicePath)->Guid);
+ ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));
+ if (TerminalDevice->TerminalType != TerminalType) {
+ Status = InitializeControllerNameTable (TerminalType, &ControllerNameTable);
+ if (!EFI_ERROR (Status)) {
+ StopTerminalStateMachine (TerminalDevice);
+ //
+ // Update the device path
+ //
+ Vendor = TerminalDevice->DevicePath;
+ Status = gBS->LocateDevicePath (&gEfiSerialIoProtocolGuid, &Vendor, &SerialIoHandle);
+ ASSERT_EFI_ERROR (Status);
+ CopyGuid (&((VENDOR_DEVICE_PATH *) Vendor)->Guid, mTerminalType[TerminalType]);
+ Status = gBS->ReinstallProtocolInterface (
+ TerminalDevice->Handle,
+ &gEfiDevicePathProtocolGuid,
+ TerminalDevice->DevicePath,
+ TerminalDevice->DevicePath
+ );
+ if (!EFI_ERROR (Status)) {
+ TerminalDevice->TerminalType = TerminalType;
+ StartTerminalStateMachine (TerminalDevice);
+ FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
+ TerminalDevice->ControllerNameTable = ControllerNameTable;
+ } else {
+ //
+ // Restore the device path on failure
+ //
+ CopyGuid (&((VENDOR_DEVICE_PATH *) Vendor)->Guid, mTerminalType[TerminalDevice->TerminalType]);
+ FreeUnicodeStringTable (ControllerNameTable);
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ FreePool (OpenInfoBuffer);
+ }
+ return Status;
+ }
+
+ //
+ // Initialize the Terminal Dev
+ //
+ TerminalDevice = AllocateCopyPool (sizeof (TERMINAL_DEV), &mTerminalDevTemplate);
+ if (TerminalDevice == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto CloseProtocols;
+ }
+
+ if (RemainingDevicePath == NULL) {
+ //
+ // If RemainingDevicePath is NULL, use default terminal type
+ //
+ TerminalDevice->TerminalType = PcdGet8 (PcdDefaultTerminalType);
+ } else {
+ //
+ // End of Device Path Node is handled in above.
+ //
+ ASSERT (!IsDevicePathEnd (RemainingDevicePath));
+ //
+ // If RemainingDevicePath isn't the End of Device Path Node,
+ // Use the RemainingDevicePath to determine the terminal type
+ //
+ TerminalDevice->TerminalType = TerminalTypeFromGuid (&((VENDOR_DEVICE_PATH *) RemainingDevicePath)->Guid);
+ }
+ ASSERT (TerminalDevice->TerminalType < ARRAY_SIZE (mTerminalType));
+ TerminalDevice->SerialIo = SerialIo;
+
+ //
+ // Build the component name for the child device
+ //
+ Status = InitializeControllerNameTable (TerminalDevice->TerminalType, &TerminalDevice->ControllerNameTable);
+ if (EFI_ERROR (Status)) {
+ goto FreeResources;
+ }
+
+ //
+ // Build the device path for the child device
+ //
+ Status = SetTerminalDevicePath (TerminalDevice->TerminalType, ParentDevicePath, &TerminalDevice->DevicePath);
+ if (EFI_ERROR (Status)) {
+ goto FreeResources;
+ }
+
+ InitializeListHead (&TerminalDevice->NotifyList);
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ TerminalConInWaitForKeyEx,
+ TerminalDevice,
+ &TerminalDevice->SimpleInputEx.WaitForKeyEx
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ TerminalConInWaitForKey,
+ TerminalDevice,
+ &TerminalDevice->SimpleInput.WaitForKey
+ );
+ ASSERT_EFI_ERROR (Status);
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ KeyNotifyProcessHandler,
+ TerminalDevice,
+ &TerminalDevice->KeyNotifyProcessEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Allocates and initializes the FIFO buffer to be zero, used for accommodating
+ // the pre-read pending characters.
+ //
+ TerminalDevice->RawFiFo = AllocateZeroPool (sizeof (RAW_DATA_FIFO));
+ if (TerminalDevice->RawFiFo == NULL) {
+ goto FreeResources;
+ }
+ TerminalDevice->UnicodeFiFo = AllocateZeroPool (sizeof (UNICODE_FIFO));
+ if (TerminalDevice->UnicodeFiFo == NULL) {
+ goto FreeResources;
+ }
+ TerminalDevice->EfiKeyFiFo = AllocateZeroPool (sizeof (EFI_KEY_FIFO));
+ if (TerminalDevice->EfiKeyFiFo == NULL) {
+ goto FreeResources;
+ }
+ TerminalDevice->EfiKeyFiFoForNotify = AllocateZeroPool (sizeof (EFI_KEY_FIFO));
+ if (TerminalDevice->EfiKeyFiFoForNotify == NULL) {
+ goto FreeResources;
+ }
+
+ //
+ // Set the timeout value of serial buffer for keystroke response performance issue
+ //
+ Mode = TerminalDevice->SerialIo->Mode;
+
+ SerialInTimeOut = 0;
+ if (Mode->BaudRate != 0) {
+ SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate;
+ }
+
+ Status = TerminalDevice->SerialIo->SetAttributes (
+ TerminalDevice->SerialIo,
+ Mode->BaudRate,
+ Mode->ReceiveFifoDepth,
+ (UINT32) SerialInTimeOut,
+ (EFI_PARITY_TYPE) (Mode->Parity),
+ (UINT8) Mode->DataBits,
+ (EFI_STOP_BITS_TYPE) (Mode->StopBits)
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // if set attributes operation fails, invalidate
+ // the value of SerialInTimeOut,thus make it
+ // inconsistent with the default timeout value
+ // of serial buffer. This will invoke the recalculation
+ // in the readkeystroke routine.
+ //
+ TerminalDevice->SerialInTimeOut = 0;
+ } else {
+ TerminalDevice->SerialInTimeOut = SerialInTimeOut;
+ }
+
+ SimpleTextOutput = &TerminalDevice->SimpleTextOutput;
+ SimpleTextInput = &TerminalDevice->SimpleInput;
+
+ //
+ // Initialize SimpleTextOut instance
+ //
+ SimpleTextOutput->Mode = &TerminalDevice->SimpleTextOutputMode;
+ TerminalDevice->TerminalConsoleModeData = InitializeTerminalConsoleTextMode (
+ &SimpleTextOutput->Mode->MaxMode
+ );
+ if (TerminalDevice->TerminalConsoleModeData == NULL) {
+ goto FreeResources;
+ }
+ //
+ // For terminal devices, cursor is always visible
+ //
+ SimpleTextOutput->Mode->CursorVisible = TRUE;
+ Status = SimpleTextOutput->SetAttribute (SimpleTextOutput, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
+ if (!EFI_ERROR (Status)) {
+ Status = SimpleTextOutput->Reset (SimpleTextOutput, FALSE);
+ }
+ if (EFI_ERROR (Status)) {
+ goto ReportError;
+ }
+
+ //
+ // Initialize SimpleTextInput instance
+ //
+ Status = SimpleTextInput->Reset (SimpleTextInput, FALSE);
+ if (EFI_ERROR (Status)) {
+ goto ReportError;
+ }
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &TerminalDevice->Handle,
+ &gEfiSimpleTextInProtocolGuid, &TerminalDevice->SimpleInput,
+ &gEfiSimpleTextInputExProtocolGuid, &TerminalDevice->SimpleInputEx,
+ &gEfiSimpleTextOutProtocolGuid, &TerminalDevice->SimpleTextOutput,
+ &gEfiDevicePathProtocolGuid, TerminalDevice->DevicePath,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ (VOID **) &TerminalDevice->SerialIo,
+ This->DriverBindingHandle,
+ TerminalDevice->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ ASSERT_EFI_ERROR (Status);
+ StartTerminalStateMachine (TerminalDevice);
+ return Status;
+ }
+
+ReportError:
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),
+ ParentDevicePath
+ );
+
+FreeResources:
+ ASSERT (TerminalDevice != NULL);
+
+ if (TerminalDevice->SimpleInput.WaitForKey != NULL) {
+ gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);
+ }
+ if (TerminalDevice->SimpleInputEx.WaitForKeyEx != NULL) {
+ gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);
+ }
+ if (TerminalDevice->KeyNotifyProcessEvent != NULL) {
+ gBS->CloseEvent (TerminalDevice->KeyNotifyProcessEvent);
+ }
+
+ if (TerminalDevice->RawFiFo != NULL) {
+ FreePool (TerminalDevice->RawFiFo);
+ }
+ if (TerminalDevice->UnicodeFiFo != NULL) {
+ FreePool (TerminalDevice->UnicodeFiFo);
+ }
+ if (TerminalDevice->EfiKeyFiFo != NULL) {
+ FreePool (TerminalDevice->EfiKeyFiFo);
+ }
+ if (TerminalDevice->EfiKeyFiFoForNotify != NULL) {
+ FreePool (TerminalDevice->EfiKeyFiFoForNotify);
+ }
+
+ if (TerminalDevice->ControllerNameTable != NULL) {
+ FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
+ }
+
+ if (TerminalDevice->DevicePath != NULL) {
+ FreePool (TerminalDevice->DevicePath);
+ }
+
+ if (TerminalDevice->TerminalConsoleModeData != NULL) {
+ FreePool (TerminalDevice->TerminalConsoleModeData);
+ }
+
+ FreePool (TerminalDevice);
+
+CloseProtocols:
+
+ //
+ // Remove Parent Device Path from
+ // the Console Device Environment Variables
+ //
+ TerminalRemoveConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME, ParentDevicePath);
+ TerminalRemoveConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
+ TerminalRemoveConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ Stop this driver on Controller by closing Simple Text In, Simple Text
+ In Ex, Simple Text Out protocol, and removing parent device path from
+ Console Device Environment Variables.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed Controller.
+ @retval other This driver could not be removed from this device.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ BOOLEAN AllChildrenStopped;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;
+ TERMINAL_DEV *TerminalDevice;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;
+
+ //
+ // Complete all outstanding transactions to Controller.
+ // Don't allow any new transaction to Controller to be started.
+ //
+ if (NumberOfChildren == 0) {
+ //
+ // Close the bus driver
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Remove Parent Device Path from
+ // the Console Device Environment Variables
+ //
+ TerminalRemoveConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME, ParentDevicePath);
+ TerminalRemoveConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
+ TerminalRemoveConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+ }
+
+ AllChildrenStopped = TRUE;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiSimpleTextOutProtocolGuid,
+ (VOID **) &SimpleTextOutput,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+
+ TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiSimpleTextInProtocolGuid,
+ &TerminalDevice->SimpleInput,
+ &gEfiSimpleTextInputExProtocolGuid,
+ &TerminalDevice->SimpleInputEx,
+ &gEfiSimpleTextOutProtocolGuid,
+ &TerminalDevice->SimpleTextOutput,
+ &gEfiDevicePathProtocolGuid,
+ TerminalDevice->DevicePath,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ (VOID **) &SerialIo,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ } else {
+
+ FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
+ StopTerminalStateMachine (TerminalDevice);
+ gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);
+ gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);
+ gBS->CloseEvent (TerminalDevice->KeyNotifyProcessEvent);
+ TerminalFreeNotifyList (&TerminalDevice->NotifyList);
+ FreePool (TerminalDevice->DevicePath);
+ FreePool (TerminalDevice->TerminalConsoleModeData);
+ FreePool (TerminalDevice);
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Compare a device path data structure to that of all the nodes of a
+ second device path instance.
+
+ @param Multi A pointer to a multi-instance device path data structure.
+ @param Single A pointer to a single-instance device path data structure.
+
+ @retval TRUE If the Single is contained within Multi.
+ @retval FALSE The Single is not match within Multi.
+
+**/
+BOOLEAN
+MatchDevicePaths (
+ IN EFI_DEVICE_PATH_PROTOCOL *Multi,
+ IN EFI_DEVICE_PATH_PROTOCOL *Single
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
+ UINTN Size;
+
+ DevicePath = Multi;
+ DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
+ //
+ // Search for the match of 'Single' in 'Multi'
+ //
+ while (DevicePathInst != NULL) {
+ //
+ // If the single device path is found in multiple device paths,
+ // return success
+ //
+ if (CompareMem (Single, DevicePathInst, Size) == 0) {
+ FreePool (DevicePathInst);
+ return TRUE;
+ }
+
+ FreePool (DevicePathInst);
+ DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
+ }
+
+ return FALSE;
+}
+
+/**
+ Update terminal device path in Console Device Environment Variables.
+
+ @param VariableName The Console Device Environment Variable.
+ @param ParentDevicePath The terminal device path to be updated.
+
+**/
+VOID
+TerminalUpdateConsoleDevVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
+ )
+{
+ EFI_STATUS Status;
+ UINTN NameSize;
+ UINTN VariableSize;
+ TERMINAL_TYPE TerminalType;
+ EFI_DEVICE_PATH_PROTOCOL *Variable;
+ EFI_DEVICE_PATH_PROTOCOL *NewVariable;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EDKII_SET_VARIABLE_STATUS *SetVariableStatus;
+
+ //
+ // Get global variable and its size according to the name given.
+ //
+ Status = GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);
+ if (Status == EFI_NOT_FOUND) {
+ Status = EFI_SUCCESS;
+ Variable = NULL;
+ }
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // Append terminal device path onto the variable.
+ //
+ for (TerminalType = 0; TerminalType < ARRAY_SIZE (mTerminalType); TerminalType++) {
+ SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);
+
+ if (TempDevicePath != NULL) {
+ if (!MatchDevicePaths (Variable, TempDevicePath)) {
+ NewVariable = AppendDevicePathInstance (Variable, TempDevicePath);
+ if (NewVariable != NULL) {
+ if (Variable != NULL) {
+ FreePool (Variable);
+ }
+ Variable = NewVariable;
+ }
+ }
+
+ FreePool (TempDevicePath);
+ }
+
+ }
+
+ VariableSize = GetDevicePathSize (Variable);
+
+ Status = gRT->SetVariable (
+ VariableName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ VariableSize,
+ Variable
+ );
+
+ if (EFI_ERROR (Status)) {
+ NameSize = StrSize (VariableName);
+ SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + VariableSize);
+ if (SetVariableStatus != NULL) {
+ CopyGuid (&SetVariableStatus->Guid, &gEfiGlobalVariableGuid);
+ SetVariableStatus->NameSize = NameSize;
+ SetVariableStatus->DataSize = VariableSize;
+ SetVariableStatus->SetStatus = Status;
+ SetVariableStatus->Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
+ CopyMem (SetVariableStatus + 1, VariableName, NameSize);
+ CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Variable, VariableSize);
+
+ REPORT_STATUS_CODE_EX (
+ EFI_ERROR_CODE,
+ PcdGet32 (PcdErrorCodeSetVariable),
+ 0,
+ NULL,
+ &gEdkiiStatusCodeDataTypeVariableGuid,
+ SetVariableStatus,
+ sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + VariableSize
+ );
+
+ FreePool (SetVariableStatus);
+ }
+ }
+
+ FreePool (Variable);
+
+ return ;
+}
+
+
+/**
+ Remove terminal device path from Console Device Environment Variables.
+
+ @param VariableName Console Device Environment Variables.
+ @param ParentDevicePath The terminal device path to be updated.
+
+**/
+VOID
+TerminalRemoveConsoleDevVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN FoundOne;
+ BOOLEAN Match;
+ UINTN VariableSize;
+ UINTN InstanceSize;
+ TERMINAL_TYPE TerminalType;
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ EFI_DEVICE_PATH_PROTOCOL *Variable;
+ EFI_DEVICE_PATH_PROTOCOL *OriginalVariable;
+ EFI_DEVICE_PATH_PROTOCOL *NewVariable;
+ EFI_DEVICE_PATH_PROTOCOL *SavedNewVariable;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+
+ Instance = NULL;
+
+ //
+ // Get global variable and its size according to the name given.
+ //
+ GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);
+ if (Variable == NULL) {
+ return ;
+ }
+
+ FoundOne = FALSE;
+ OriginalVariable = Variable;
+ NewVariable = NULL;
+
+ //
+ // Get first device path instance from Variable
+ //
+ Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);
+ if (Instance == NULL) {
+ FreePool (OriginalVariable);
+ return ;
+ }
+ //
+ // Loop through all the device path instances of Variable
+ //
+ do {
+ //
+ // Loop through all the terminal types that this driver supports
+ //
+ Match = FALSE;
+ for (TerminalType = 0; TerminalType < ARRAY_SIZE (mTerminalType); TerminalType++) {
+
+ SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);
+
+ //
+ // Compare the generated device path to the current device path instance
+ //
+ if (TempDevicePath != NULL) {
+ if (CompareMem (Instance, TempDevicePath, InstanceSize) == 0) {
+ Match = TRUE;
+ FoundOne = TRUE;
+ }
+
+ FreePool (TempDevicePath);
+ }
+ }
+ //
+ // If a match was not found, then keep the current device path instance
+ //
+ if (!Match) {
+ SavedNewVariable = NewVariable;
+ NewVariable = AppendDevicePathInstance (NewVariable, Instance);
+ if (SavedNewVariable != NULL) {
+ FreePool (SavedNewVariable);
+ }
+ }
+ //
+ // Get next device path instance from Variable
+ //
+ FreePool (Instance);
+ Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);
+ } while (Instance != NULL);
+
+ FreePool (OriginalVariable);
+
+ if (FoundOne) {
+ VariableSize = GetDevicePathSize (NewVariable);
+
+ Status = gRT->SetVariable (
+ VariableName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ VariableSize,
+ NewVariable
+ );
+ //
+ // Shrinking variable with existing variable driver implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if (NewVariable != NULL) {
+ FreePool (NewVariable);
+ }
+
+ return ;
+}
+
+/**
+ Build terminal device path according to terminal type.
+
+ @param TerminalType The terminal type is PC ANSI, VT100, VT100+ or VT-UTF8.
+ @param ParentDevicePath Parent device path.
+ @param TerminalDevicePath Returned terminal device path, if building successfully.
+
+ @retval EFI_UNSUPPORTED Terminal does not belong to the supported type.
+ @retval EFI_OUT_OF_RESOURCES Generate terminal device path failed.
+ @retval EFI_SUCCESS Build terminal device path successfully.
+
+**/
+EFI_STATUS
+SetTerminalDevicePath (
+ IN TERMINAL_TYPE TerminalType,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **TerminalDevicePath
+ )
+{
+ VENDOR_DEVICE_PATH Node;
+
+ ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));
+ Node.Header.Type = MESSAGING_DEVICE_PATH;
+ Node.Header.SubType = MSG_VENDOR_DP;
+ SetDevicePathNodeLength (&Node.Header, sizeof (VENDOR_DEVICE_PATH));
+ CopyGuid (&Node.Guid, mTerminalType[TerminalType]);
+
+ //
+ // Append the terminal node onto parent device path
+ // to generate a complete terminal device path.
+ //
+ *TerminalDevicePath = AppendDevicePathNode (
+ ParentDevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &Node
+ );
+ if (*TerminalDevicePath == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The user Entry Point for module Terminal. The user code starts with this function.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeTerminal(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gTerminalDriverBinding,
+ ImageHandle,
+ &gTerminalComponentName,
+ &gTerminalComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Check if the device supports hot-plug through its device path.
+
+ This function could be updated to check more types of Hot Plug devices.
+ Currently, it checks USB and PCCard device.
+
+ @param DevicePath Pointer to device's device path.
+
+ @retval TRUE The devcie is a hot-plug device
+ @retval FALSE The devcie is not a hot-plug device.
+
+**/
+BOOLEAN
+IsHotPlugDevice (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *CheckDevicePath;
+
+ CheckDevicePath = DevicePath;
+ while (!IsDevicePathEnd (CheckDevicePath)) {
+ //
+ // Check device whether is hot plug device or not throught Device Path
+ //
+ if ((DevicePathType (CheckDevicePath) == MESSAGING_DEVICE_PATH) &&
+ (DevicePathSubType (CheckDevicePath) == MSG_USB_DP ||
+ DevicePathSubType (CheckDevicePath) == MSG_USB_CLASS_DP ||
+ DevicePathSubType (CheckDevicePath) == MSG_USB_WWID_DP)) {
+ //
+ // If Device is USB device
+ //
+ return TRUE;
+ }
+ if ((DevicePathType (CheckDevicePath) == HARDWARE_DEVICE_PATH) &&
+ (DevicePathSubType (CheckDevicePath) == HW_PCCARD_DP)) {
+ //
+ // If Device is PCCard
+ //
+ return TRUE;
+ }
+
+ CheckDevicePath = NextDevicePathNode (CheckDevicePath);
+ }
+
+ return FALSE;
+}
+