+ @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, &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
+ @param[out] TextModeData The buffer to the text modes column and row information.\r
+ Caller is responsible to free it when it's non-NULL.\r
+\r
+ @retval EFI_SUCCESS The supporting mode information is returned.\r
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeTerminalConsoleTextMode (\r
+ OUT UINTN *TextModeCount,\r
+ OUT TERMINAL_CONSOLE_MODE_DATA **TextModeData\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINTN Count;\r
+ TERMINAL_CONSOLE_MODE_DATA *ModeBuffer;\r
+ TERMINAL_CONSOLE_MODE_DATA *NewModeBuffer;\r
+ UINTN ValidCount;\r
+ UINTN ValidIndex;\r
+ \r
+ if ((TextModeCount == NULL) || (TextModeData == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ \r
+ Count = sizeof (mTerminalConsoleModeData) / sizeof (TERMINAL_CONSOLE_MODE_DATA);\r
+ \r
+ //\r
+ // Get defined mode buffer pointer.\r
+ //\r
+ ModeBuffer = mTerminalConsoleModeData;\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
+ NewModeBuffer = AllocateZeroPool (sizeof (TERMINAL_CONSOLE_MODE_DATA) * (Count + 2));\r
+ ASSERT (NewModeBuffer != NULL);\r
+\r
+ //\r
+ // Mode 0 and mode 1 is for 80x25, 80x50 according to UEFI spec.\r
+ //\r
+ ValidCount = 0; \r
+\r
+ NewModeBuffer[ValidCount].Columns = 80;\r
+ NewModeBuffer[ValidCount].Rows = 25;\r
+ ValidCount++;\r
+\r
+ NewModeBuffer[ValidCount].Columns = 80;\r
+ NewModeBuffer[ValidCount].Rows = 50;\r
+ ValidCount++;\r
+ \r
+ //\r
+ // Start from mode 2 to put the valid mode other than 80x25 and 80x50 in the output mode buffer.\r
+ //\r
+ for (Index = 0; Index < Count; Index++) {\r
+ if ((ModeBuffer[Index].Columns == 0) || (ModeBuffer[Index].Rows == 0)) {\r
+ //\r
+ // Skip the pre-defined mode which is invalid.\r
+ //\r
+ continue;\r
+ }\r
+ for (ValidIndex = 0; ValidIndex < ValidCount; ValidIndex++) {\r
+ if ((ModeBuffer[Index].Columns == NewModeBuffer[ValidIndex].Columns) &&\r
+ (ModeBuffer[Index].Rows == NewModeBuffer[ValidIndex].Rows)) {\r
+ //\r
+ // Skip the duplicated mode.\r
+ //\r
+ break;\r
+ }\r
+ }\r
+ if (ValidIndex == ValidCount) {\r
+ NewModeBuffer[ValidCount].Columns = ModeBuffer[Index].Columns;\r
+ NewModeBuffer[ValidCount].Rows = ModeBuffer[Index].Rows;\r
+ ValidCount++;\r
+ }\r
+ }\r
+ \r
+ DEBUG_CODE (\r
+ for (Index = 0; Index < ValidCount; Index++) {\r
+ DEBUG ((EFI_D_INFO, "Terminal - Mode %d, Column = %d, Row = %d\n", \r
+ Index, NewModeBuffer[Index].Columns, NewModeBuffer[Index].Rows)); \r
+ }\r
+ );\r
+ \r
+ //\r
+ // Return valid mode count and mode information buffer.\r
+ //\r
+ *TextModeCount = ValidCount;\r
+ *TextModeData = NewModeBuffer;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Start this driver on Controller by opening a Serial IO protocol,\r
+ reading Device Path, and creating a child handle with a Simple Text In,\r
+ Simple Text In Ex and Simple Text Out protocol, and device path protocol.\r
+ And store Console Device Environment Variables.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to bind driver to\r
+ @param RemainingDevicePath Optional parameter use to pick a specific child\r
+ device to start.\r
+\r
+ @retval EFI_SUCCESS This driver is added to Controller.\r
+ @retval EFI_ALREADY_STARTED This driver is already running on Controller.\r
+ @retval other This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TerminalDriverBindingStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r