+{\r
+ EFI_DEVICE_PATH_PROTOCOL *TerminalDevicePath;\r
+ TERMINAL_TYPE TerminalType;\r
+ VENDOR_DEVICE_PATH *Node;\r
+ EFI_STATUS Status;\r
+\r
+ TerminalDevicePath = NULL;\r
+\r
+ //\r
+ // Use the RemainingDevicePath to determine the terminal type\r
+ //\r
+ Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;\r
+ if (Node == NULL) {\r
+ TerminalType = PcdGet8 (PcdDefaultTerminalType);\r
+\r
+ } else if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) {\r
+\r
+ TerminalType = TerminalTypePcAnsi;\r
+\r
+ } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) {\r
+\r
+ TerminalType = TerminalTypeVt100;\r
+\r
+ } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) {\r
+\r
+ TerminalType = TerminalTypeVt100Plus;\r
+\r
+ } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {\r
+\r
+ TerminalType = TerminalTypeVtUtf8;\r
+\r
+ } else if (CompareGuid (&Node->Guid, &gEfiTtyTermGuid)) {\r
+\r
+ TerminalType = TerminalTypeTtyTerm;\r
+\r
+ } else {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Build the device path for the child device\r
+ //\r
+ Status = SetTerminalDevicePath (\r
+ TerminalType,\r
+ ParentDevicePath,\r
+ &TerminalDevicePath\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+ return TerminalDevicePath;\r
+}\r
+\r
+/**\r
+ Compare a device path data structure to that of all the nodes of a\r
+ second device path instance.\r
+\r
+ @param Multi A pointer to a multi-instance device path data structure.\r
+ @param Single A pointer to a single-instance device path data structure.\r
+\r
+ @retval TRUE If the Single is contained within Multi.\r
+ @retval FALSE The Single is not match within Multi.\r
+\r
+**/\r
+BOOLEAN\r
+MatchDevicePaths (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *Multi,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *Single\r
+ )\r
+{\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;\r
+ UINTN Size;\r
+\r
+ DevicePath = Multi;\r
+ DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);\r
+ //\r
+ // Search for the match of 'Single' in 'Multi'\r
+ //\r
+ while (DevicePathInst != NULL) {\r
+ //\r
+ // If the single device path is found in multiple device paths,\r
+ // return success\r
+ //\r
+ if (CompareMem (Single, DevicePathInst, Size) == 0) {\r
+ FreePool (DevicePathInst);\r
+ return TRUE;\r
+ }\r
+\r
+ FreePool (DevicePathInst);\r
+ DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Check whether the terminal device path is in the global variable.\r
+\r
+ @param VariableName Pointer to one global variable.\r
+ @param TerminalDevicePath Pointer to the terminal device's device path.\r
+\r
+ @retval TRUE The devcie is in the global variable.\r
+ @retval FALSE The devcie is not in the global variable.\r
+\r
+**/\r
+BOOLEAN\r
+IsTerminalInConsoleVariable (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *TerminalDevicePath\r
+ )\r
+{\r
+ EFI_DEVICE_PATH_PROTOCOL *Variable;\r
+ BOOLEAN ReturnFlag;\r
+\r
+ //\r
+ // Get global variable and its size according to the name given.\r
+ //\r
+ GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);\r
+ if (Variable == NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Check whether the terminal device path is one of the variable instances.\r
+ //\r
+ ReturnFlag = MatchDevicePaths (Variable, TerminalDevicePath);\r
+\r
+ FreePool (Variable);\r
+\r
+ return ReturnFlag;\r
+}\r
+\r
+/**\r
+ Free notify functions list.\r
+\r
+ @param ListHead The list head\r
+\r
+ @retval EFI_SUCCESS Free the notify list successfully.\r
+ @retval EFI_INVALID_PARAMETER ListHead is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+TerminalFreeNotifyList (\r
+ IN OUT LIST_ENTRY *ListHead\r
+ )\r
+{\r
+ TERMINAL_CONSOLE_IN_EX_NOTIFY *NotifyNode;\r
+\r
+ if (ListHead == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ while (!IsListEmpty (ListHead)) {\r
+ NotifyNode = CR (\r
+ ListHead->ForwardLink,\r
+ TERMINAL_CONSOLE_IN_EX_NOTIFY,\r
+ NotifyEntry,\r
+ TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
+ );\r
+ RemoveEntryList (ListHead->ForwardLink);\r
+ FreePool (NotifyNode);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Initialize all the text modes which the terminal console supports.\r
+\r
+ It returns information for available text modes that the terminal can support.\r
+\r
+ @param[out] TextModeCount The total number of text modes that terminal console supports.\r
+\r
+ @return The buffer to the text modes column and row information.\r
+ Caller is responsible to free it when it's non-NULL.\r
+\r
+**/\r
+TERMINAL_CONSOLE_MODE_DATA *\r
+InitializeTerminalConsoleTextMode (\r
+ OUT INT32 *TextModeCount\r
+)\r
+{\r
+ TERMINAL_CONSOLE_MODE_DATA *TextModeData;\r
+\r
+ ASSERT (TextModeCount != NULL);\r
+\r
+ //\r
+ // Here we make sure that the final mode exposed does not include the duplicated modes,\r
+ // and does not include the invalid modes which exceed the max column and row.\r
+ // Reserve 2 modes for 80x25, 80x50 of terminal console.\r
+ //\r
+ TextModeData = AllocateCopyPool (sizeof (mTerminalConsoleModeData), mTerminalConsoleModeData);\r
+ if (TextModeData == NULL) {\r
+ return NULL;\r
+ }\r
+ *TextModeCount = ARRAY_SIZE (mTerminalConsoleModeData);\r
+\r
+ DEBUG_CODE (\r
+ INT32 Index;\r
+ for (Index = 0; Index < *TextModeCount; Index++) {\r
+ DEBUG ((DEBUG_INFO, "Terminal - Mode %d, Column = %d, Row = %d\n",\r
+ Index, TextModeData[Index].Columns, TextModeData[Index].Rows));\r
+ }\r
+ );\r
+ return TextModeData;\r
+}\r
+\r
+/**\r
+ Stop the terminal state machine.\r
+\r
+ @param TerminalDevice The terminal device.\r
+**/\r
+VOID\r
+StopTerminalStateMachine (\r
+ TERMINAL_DEV *TerminalDevice\r
+ )\r
+{\r
+ EFI_TPL OriginalTpl;\r
+\r
+ OriginalTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+ gBS->CloseEvent (TerminalDevice->TimerEvent);\r
+ gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);\r
+\r
+ gBS->RestoreTPL (OriginalTpl);\r
+}\r
+\r
+/**\r
+ Start the terminal state machine.\r
+\r
+ @param TerminalDevice The terminal device.\r
+**/\r
+VOID\r
+StartTerminalStateMachine (\r
+ TERMINAL_DEV *TerminalDevice\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ Status = gBS->CreateEvent (\r
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ TerminalConInTimerHandler,\r
+ TerminalDevice,\r
+ &TerminalDevice->TimerEvent\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = gBS->SetTimer (\r
+ TerminalDevice->TimerEvent,\r
+ TimerPeriodic,\r
+ KEYBOARD_TIMER_INTERVAL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r