| /** @file | |
| Produces Simple Text Input Protocol, Simple Text Input Extended Protocol and | |
| Simple Text Output Protocol upon Serial IO Protocol. | |
| Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> | |
| 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. | |
| **/ | |
| #include "Terminal.h" | |
| // | |
| // Globals | |
| // | |
| EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding = { | |
| TerminalDriverBindingSupported, | |
| TerminalDriverBindingStart, | |
| TerminalDriverBindingStop, | |
| 0xa, | |
| NULL, | |
| NULL | |
| }; | |
| EFI_GUID *mTerminalType[] = { | |
| &gEfiPcAnsiGuid, | |
| &gEfiVT100Guid, | |
| &gEfiVT100PlusGuid, | |
| &gEfiVTUTF8Guid, | |
| &gEfiTtyTermGuid | |
| }; | |
| 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" | |
| }; | |
| 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, and TtyTerm 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; | |
| } | |