2 Produces Simple Text Input Protocol, Simple Text Input Extended Protocol and
3 Simple Text Output Protocol upon Serial IO Protocol.
5 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
16 EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding
= {
17 TerminalDriverBindingSupported
,
18 TerminalDriverBindingStart
,
19 TerminalDriverBindingStop
,
26 EFI_GUID
*mTerminalType
[] = {
39 CHAR16
*mSerialConsoleNames
[] = {
40 L
"PC-ANSI Serial Console",
41 L
"VT-100 Serial Console",
42 L
"VT-100+ Serial Console",
43 L
"VT-UTF8 Serial Console",
44 L
"Tty Terminal Serial Console",
45 L
"Linux Terminal Serial Console",
46 L
"Xterm R6 Serial Console",
47 L
"VT-400 Serial Console",
48 L
"SCO Terminal Serial Console"
51 TERMINAL_DEV mTerminalDevTemplate
= {
52 TERMINAL_DEV_SIGNATURE
,
59 TerminalConInReadKeyStroke
,
64 TerminalConOutOutputString
,
65 TerminalConOutTestString
,
66 TerminalConOutQueryMode
,
67 TerminalConOutSetMode
,
68 TerminalConOutSetAttribute
,
69 TerminalConOutClearScreen
,
70 TerminalConOutSetCursorPosition
,
71 TerminalConOutEnableCursor
,
74 { // SimpleTextOutputMode
77 EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
), // Attribute
82 NULL
, // TerminalConsoleModeData
88 NULL
, // EfiKeyFiFoForNotify
90 NULL
, // ControllerNameTable
92 NULL
, // TwoSecondTimeOut
102 { // SimpleTextInputEx
103 TerminalConInResetEx
,
104 TerminalConInReadKeyStrokeEx
,
106 TerminalConInSetState
,
107 TerminalConInRegisterKeyNotify
,
108 TerminalConInUnregisterKeyNotify
,
114 NULL
// KeyNotifyProcessEvent
117 TERMINAL_CONSOLE_MODE_DATA mTerminalConsoleModeData
[] = {
122 // New modes can be added here.
127 Convert the GUID representation of terminal type to enum type.
129 @param Guid The GUID representation of terminal type.
131 @return The terminal type in enum type.
134 TerminalTypeFromGuid (
140 for (Type
= 0; Type
< ARRAY_SIZE (mTerminalType
); Type
++) {
141 if (CompareGuid (Guid
, mTerminalType
[Type
])) {
149 Test to see if this driver supports Controller.
151 @param This Protocol instance pointer.
152 @param Controller Handle of device to test
153 @param RemainingDevicePath Optional parameter use to pick a specific child
156 @retval EFI_SUCCESS This driver supports this device.
157 @retval EFI_ALREADY_STARTED This driver is already running on this device.
158 @retval other This driver does not support this device.
163 TerminalDriverBindingSupported (
164 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
165 IN EFI_HANDLE Controller
,
166 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
170 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
171 EFI_SERIAL_IO_PROTOCOL
*SerialIo
;
172 VENDOR_DEVICE_PATH
*Node
;
175 // If remaining device path is not NULL, then make sure it is a
176 // device path that describes a terminal communications protocol.
178 if (RemainingDevicePath
!= NULL
) {
180 // Check if RemainingDevicePath is the End of Device Path Node,
181 // if yes, go on checking other conditions
183 if (!IsDevicePathEnd (RemainingDevicePath
)) {
185 // If RemainingDevicePath isn't the End of Device Path Node,
186 // check its validation
188 Node
= (VENDOR_DEVICE_PATH
*) RemainingDevicePath
;
190 if (Node
->Header
.Type
!= MESSAGING_DEVICE_PATH
||
191 Node
->Header
.SubType
!= MSG_VENDOR_DP
||
192 DevicePathNodeLength(&Node
->Header
) != sizeof(VENDOR_DEVICE_PATH
)) {
194 return EFI_UNSUPPORTED
;
198 // only supports PC ANSI, VT100, VT100+, VT-UTF8, TtyTerm
199 // Linux, XtermR6, VT400 and SCO terminal types
201 if (TerminalTypeFromGuid (&Node
->Guid
) == ARRAY_SIZE (mTerminalType
)) {
202 return EFI_UNSUPPORTED
;
207 // Open the IO Abstraction(s) needed to perform the supported test
208 // The Controller must support the Serial I/O Protocol.
209 // This driver is a bus driver with at most 1 child device, so it is
210 // ok for it to be already started.
212 Status
= gBS
->OpenProtocol (
214 &gEfiSerialIoProtocolGuid
,
216 This
->DriverBindingHandle
,
218 EFI_OPEN_PROTOCOL_BY_DRIVER
220 if (Status
== EFI_ALREADY_STARTED
) {
224 if (EFI_ERROR (Status
)) {
229 // Close the I/O Abstraction(s) used to perform the supported test
233 &gEfiSerialIoProtocolGuid
,
234 This
->DriverBindingHandle
,
239 // Open the EFI Device Path protocol needed to perform the supported test
241 Status
= gBS
->OpenProtocol (
243 &gEfiDevicePathProtocolGuid
,
244 (VOID
**) &ParentDevicePath
,
245 This
->DriverBindingHandle
,
247 EFI_OPEN_PROTOCOL_BY_DRIVER
249 if (Status
== EFI_ALREADY_STARTED
) {
253 if (EFI_ERROR (Status
)) {
258 // Close protocol, don't use device path protocol in the Support() function
262 &gEfiDevicePathProtocolGuid
,
263 This
->DriverBindingHandle
,
272 Free notify functions list.
274 @param ListHead The list head
276 @retval EFI_SUCCESS Free the notify list successfully.
277 @retval EFI_INVALID_PARAMETER ListHead is NULL.
281 TerminalFreeNotifyList (
282 IN OUT LIST_ENTRY
*ListHead
285 TERMINAL_CONSOLE_IN_EX_NOTIFY
*NotifyNode
;
287 if (ListHead
== NULL
) {
288 return EFI_INVALID_PARAMETER
;
290 while (!IsListEmpty (ListHead
)) {
292 ListHead
->ForwardLink
,
293 TERMINAL_CONSOLE_IN_EX_NOTIFY
,
295 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
297 RemoveEntryList (ListHead
->ForwardLink
);
298 FreePool (NotifyNode
);
305 Initialize all the text modes which the terminal console supports.
307 It returns information for available text modes that the terminal can support.
309 @param[out] TextModeCount The total number of text modes that terminal console supports.
311 @return The buffer to the text modes column and row information.
312 Caller is responsible to free it when it's non-NULL.
315 TERMINAL_CONSOLE_MODE_DATA
*
316 InitializeTerminalConsoleTextMode (
317 OUT INT32
*TextModeCount
320 TERMINAL_CONSOLE_MODE_DATA
*TextModeData
;
322 ASSERT (TextModeCount
!= NULL
);
324 TextModeData
= AllocateCopyPool (sizeof (mTerminalConsoleModeData
), mTerminalConsoleModeData
);
325 if (TextModeData
== NULL
) {
328 *TextModeCount
= ARRAY_SIZE (mTerminalConsoleModeData
);
332 for (Index
= 0; Index
< *TextModeCount
; Index
++) {
333 DEBUG ((DEBUG_INFO
, "Terminal - Mode %d, Column = %d, Row = %d\n",
334 Index
, TextModeData
[Index
].Columns
, TextModeData
[Index
].Rows
));
341 Stop the terminal state machine.
343 @param TerminalDevice The terminal device.
346 StopTerminalStateMachine (
347 TERMINAL_DEV
*TerminalDevice
352 OriginalTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
354 gBS
->CloseEvent (TerminalDevice
->TimerEvent
);
355 gBS
->CloseEvent (TerminalDevice
->TwoSecondTimeOut
);
357 gBS
->RestoreTPL (OriginalTpl
);
361 Start the terminal state machine.
363 @param TerminalDevice The terminal device.
366 StartTerminalStateMachine (
367 TERMINAL_DEV
*TerminalDevice
371 Status
= gBS
->CreateEvent (
372 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
374 TerminalConInTimerHandler
,
376 &TerminalDevice
->TimerEvent
378 ASSERT_EFI_ERROR (Status
);
380 Status
= gBS
->SetTimer (
381 TerminalDevice
->TimerEvent
,
383 KEYBOARD_TIMER_INTERVAL
385 ASSERT_EFI_ERROR (Status
);
387 Status
= gBS
->CreateEvent (
392 &TerminalDevice
->TwoSecondTimeOut
394 ASSERT_EFI_ERROR (Status
);
398 Initialize the controller name table.
400 @param TerminalType The terminal type.
401 @param ControllerNameTable The controller name table.
403 @retval EFI_SUCCESS The controller name table is initialized successfully.
404 @retval others Return status of AddUnicodeString2 ().
407 InitializeControllerNameTable (
408 TERMINAL_TYPE TerminalType
,
409 EFI_UNICODE_STRING_TABLE
**ControllerNameTable
413 EFI_UNICODE_STRING_TABLE
*Table
;
415 ASSERT (TerminalType
< ARRAY_SIZE (mTerminalType
));
417 Status
= AddUnicodeString2 (
419 gTerminalComponentName
.SupportedLanguages
,
421 mSerialConsoleNames
[TerminalType
],
424 if (!EFI_ERROR (Status
)) {
425 Status
= AddUnicodeString2 (
427 gTerminalComponentName2
.SupportedLanguages
,
429 mSerialConsoleNames
[TerminalType
],
432 if (EFI_ERROR (Status
)) {
433 FreeUnicodeStringTable (Table
);
436 if (!EFI_ERROR (Status
)) {
437 *ControllerNameTable
= Table
;
443 Start this driver on Controller by opening a Serial IO protocol,
444 reading Device Path, and creating a child handle with a Simple Text In,
445 Simple Text In Ex and Simple Text Out protocol, and device path protocol.
446 And store Console Device Environment Variables.
448 @param This Protocol instance pointer.
449 @param Controller Handle of device to bind driver to
450 @param RemainingDevicePath Optional parameter use to pick a specific child
453 @retval EFI_SUCCESS This driver is added to Controller.
454 @retval EFI_ALREADY_STARTED This driver is already running on Controller.
455 @retval other This driver does not support this device.
460 TerminalDriverBindingStart (
461 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
462 IN EFI_HANDLE Controller
,
463 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
467 EFI_SERIAL_IO_PROTOCOL
*SerialIo
;
468 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
469 EFI_DEVICE_PATH_PROTOCOL
*Vendor
;
470 EFI_HANDLE SerialIoHandle
;
471 EFI_SERIAL_IO_MODE
*Mode
;
472 UINTN SerialInTimeOut
;
473 TERMINAL_DEV
*TerminalDevice
;
475 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
*OpenInfoBuffer
;
478 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*SimpleTextOutput
;
479 EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*SimpleTextInput
;
480 EFI_UNICODE_STRING_TABLE
*ControllerNameTable
;
483 // Get the Device Path Protocol to build the device path of the child device
485 Status
= gBS
->OpenProtocol (
487 &gEfiDevicePathProtocolGuid
,
488 (VOID
**) &ParentDevicePath
,
489 This
->DriverBindingHandle
,
491 EFI_OPEN_PROTOCOL_BY_DRIVER
493 ASSERT ((Status
== EFI_SUCCESS
) || (Status
== EFI_ALREADY_STARTED
));
494 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
499 // Open the Serial I/O Protocol BY_DRIVER. It might already be started.
501 Status
= gBS
->OpenProtocol (
503 &gEfiSerialIoProtocolGuid
,
505 This
->DriverBindingHandle
,
507 EFI_OPEN_PROTOCOL_BY_DRIVER
509 ASSERT ((Status
== EFI_SUCCESS
) || (Status
== EFI_ALREADY_STARTED
));
510 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
514 if (!IsHotPlugDevice (ParentDevicePath
)) {
516 // if the serial device is a hot plug device, do not update the
517 // ConInDev, ConOutDev, and StdErrDev variables.
519 TerminalUpdateConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME
, ParentDevicePath
);
520 TerminalUpdateConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME
, ParentDevicePath
);
521 TerminalUpdateConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME
, ParentDevicePath
);
525 // Do not create any child for END remaining device path.
527 if ((RemainingDevicePath
!= NULL
) && IsDevicePathEnd (RemainingDevicePath
)) {
531 if (Status
== EFI_ALREADY_STARTED
) {
533 if (RemainingDevicePath
== NULL
) {
535 // If RemainingDevicePath is NULL or is the End of Device Path Node
541 // This driver can only produce one child per serial port.
542 // Change its terminal type as remaining device path requests.
544 Status
= gBS
->OpenProtocolInformation (
546 &gEfiSerialIoProtocolGuid
,
550 if (!EFI_ERROR (Status
)) {
551 Status
= EFI_NOT_FOUND
;
552 for (Index
= 0; Index
< EntryCount
; Index
++) {
553 if ((OpenInfoBuffer
[Index
].Attributes
& EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
) != 0) {
554 Status
= gBS
->OpenProtocol (
555 OpenInfoBuffer
[Index
].ControllerHandle
,
556 &gEfiSimpleTextInProtocolGuid
,
557 (VOID
**) &SimpleTextInput
,
558 This
->DriverBindingHandle
,
560 EFI_OPEN_PROTOCOL_GET_PROTOCOL
562 if (!EFI_ERROR (Status
)) {
563 TerminalDevice
= TERMINAL_CON_IN_DEV_FROM_THIS (SimpleTextInput
);
564 TerminalType
= TerminalTypeFromGuid (&((VENDOR_DEVICE_PATH
*) RemainingDevicePath
)->Guid
);
565 ASSERT (TerminalType
< ARRAY_SIZE (mTerminalType
));
566 if (TerminalDevice
->TerminalType
!= TerminalType
) {
567 Status
= InitializeControllerNameTable (TerminalType
, &ControllerNameTable
);
568 if (!EFI_ERROR (Status
)) {
569 StopTerminalStateMachine (TerminalDevice
);
571 // Update the device path
573 Vendor
= TerminalDevice
->DevicePath
;
574 Status
= gBS
->LocateDevicePath (&gEfiSerialIoProtocolGuid
, &Vendor
, &SerialIoHandle
);
575 ASSERT_EFI_ERROR (Status
);
576 CopyGuid (&((VENDOR_DEVICE_PATH
*) Vendor
)->Guid
, mTerminalType
[TerminalType
]);
577 Status
= gBS
->ReinstallProtocolInterface (
578 TerminalDevice
->Handle
,
579 &gEfiDevicePathProtocolGuid
,
580 TerminalDevice
->DevicePath
,
581 TerminalDevice
->DevicePath
583 if (!EFI_ERROR (Status
)) {
584 TerminalDevice
->TerminalType
= TerminalType
;
585 StartTerminalStateMachine (TerminalDevice
);
586 FreeUnicodeStringTable (TerminalDevice
->ControllerNameTable
);
587 TerminalDevice
->ControllerNameTable
= ControllerNameTable
;
590 // Restore the device path on failure
592 CopyGuid (&((VENDOR_DEVICE_PATH
*) Vendor
)->Guid
, mTerminalType
[TerminalDevice
->TerminalType
]);
593 FreeUnicodeStringTable (ControllerNameTable
);
601 FreePool (OpenInfoBuffer
);
607 // Initialize the Terminal Dev
609 TerminalDevice
= AllocateCopyPool (sizeof (TERMINAL_DEV
), &mTerminalDevTemplate
);
610 if (TerminalDevice
== NULL
) {
611 Status
= EFI_OUT_OF_RESOURCES
;
615 if (RemainingDevicePath
== NULL
) {
617 // If RemainingDevicePath is NULL, use default terminal type
619 TerminalDevice
->TerminalType
= PcdGet8 (PcdDefaultTerminalType
);
622 // End of Device Path Node is handled in above.
624 ASSERT (!IsDevicePathEnd (RemainingDevicePath
));
626 // If RemainingDevicePath isn't the End of Device Path Node,
627 // Use the RemainingDevicePath to determine the terminal type
629 TerminalDevice
->TerminalType
= TerminalTypeFromGuid (&((VENDOR_DEVICE_PATH
*) RemainingDevicePath
)->Guid
);
631 ASSERT (TerminalDevice
->TerminalType
< ARRAY_SIZE (mTerminalType
));
632 TerminalDevice
->SerialIo
= SerialIo
;
635 // Build the component name for the child device
637 Status
= InitializeControllerNameTable (TerminalDevice
->TerminalType
, &TerminalDevice
->ControllerNameTable
);
638 if (EFI_ERROR (Status
)) {
643 // Build the device path for the child device
645 Status
= SetTerminalDevicePath (TerminalDevice
->TerminalType
, ParentDevicePath
, &TerminalDevice
->DevicePath
);
646 if (EFI_ERROR (Status
)) {
650 InitializeListHead (&TerminalDevice
->NotifyList
);
651 Status
= gBS
->CreateEvent (
654 TerminalConInWaitForKeyEx
,
656 &TerminalDevice
->SimpleInputEx
.WaitForKeyEx
658 ASSERT_EFI_ERROR (Status
);
660 Status
= gBS
->CreateEvent (
663 TerminalConInWaitForKey
,
665 &TerminalDevice
->SimpleInput
.WaitForKey
667 ASSERT_EFI_ERROR (Status
);
668 Status
= gBS
->CreateEvent (
671 KeyNotifyProcessHandler
,
673 &TerminalDevice
->KeyNotifyProcessEvent
675 ASSERT_EFI_ERROR (Status
);
678 // Allocates and initializes the FIFO buffer to be zero, used for accommodating
679 // the pre-read pending characters.
681 TerminalDevice
->RawFiFo
= AllocateZeroPool (sizeof (RAW_DATA_FIFO
));
682 if (TerminalDevice
->RawFiFo
== NULL
) {
685 TerminalDevice
->UnicodeFiFo
= AllocateZeroPool (sizeof (UNICODE_FIFO
));
686 if (TerminalDevice
->UnicodeFiFo
== NULL
) {
689 TerminalDevice
->EfiKeyFiFo
= AllocateZeroPool (sizeof (EFI_KEY_FIFO
));
690 if (TerminalDevice
->EfiKeyFiFo
== NULL
) {
693 TerminalDevice
->EfiKeyFiFoForNotify
= AllocateZeroPool (sizeof (EFI_KEY_FIFO
));
694 if (TerminalDevice
->EfiKeyFiFoForNotify
== NULL
) {
699 // Set the timeout value of serial buffer for keystroke response performance issue
701 Mode
= TerminalDevice
->SerialIo
->Mode
;
704 if (Mode
->BaudRate
!= 0) {
705 SerialInTimeOut
= (1 + Mode
->DataBits
+ Mode
->StopBits
) * 2 * 1000000 / (UINTN
) Mode
->BaudRate
;
708 Status
= TerminalDevice
->SerialIo
->SetAttributes (
709 TerminalDevice
->SerialIo
,
711 Mode
->ReceiveFifoDepth
,
712 (UINT32
) SerialInTimeOut
,
713 (EFI_PARITY_TYPE
) (Mode
->Parity
),
714 (UINT8
) Mode
->DataBits
,
715 (EFI_STOP_BITS_TYPE
) (Mode
->StopBits
)
717 if (EFI_ERROR (Status
)) {
719 // if set attributes operation fails, invalidate
720 // the value of SerialInTimeOut,thus make it
721 // inconsistent with the default timeout value
722 // of serial buffer. This will invoke the recalculation
723 // in the readkeystroke routine.
725 TerminalDevice
->SerialInTimeOut
= 0;
727 TerminalDevice
->SerialInTimeOut
= SerialInTimeOut
;
730 SimpleTextOutput
= &TerminalDevice
->SimpleTextOutput
;
731 SimpleTextInput
= &TerminalDevice
->SimpleInput
;
734 // Initialize SimpleTextOut instance
736 SimpleTextOutput
->Mode
= &TerminalDevice
->SimpleTextOutputMode
;
737 TerminalDevice
->TerminalConsoleModeData
= InitializeTerminalConsoleTextMode (
738 &SimpleTextOutput
->Mode
->MaxMode
740 if (TerminalDevice
->TerminalConsoleModeData
== NULL
) {
744 // For terminal devices, cursor is always visible
746 SimpleTextOutput
->Mode
->CursorVisible
= TRUE
;
747 Status
= SimpleTextOutput
->SetAttribute (SimpleTextOutput
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
748 if (!EFI_ERROR (Status
)) {
749 Status
= SimpleTextOutput
->Reset (SimpleTextOutput
, FALSE
);
751 if (EFI_ERROR (Status
)) {
756 // Initialize SimpleTextInput instance
758 Status
= SimpleTextInput
->Reset (SimpleTextInput
, FALSE
);
759 if (EFI_ERROR (Status
)) {
763 Status
= gBS
->InstallMultipleProtocolInterfaces (
764 &TerminalDevice
->Handle
,
765 &gEfiSimpleTextInProtocolGuid
, &TerminalDevice
->SimpleInput
,
766 &gEfiSimpleTextInputExProtocolGuid
, &TerminalDevice
->SimpleInputEx
,
767 &gEfiSimpleTextOutProtocolGuid
, &TerminalDevice
->SimpleTextOutput
,
768 &gEfiDevicePathProtocolGuid
, TerminalDevice
->DevicePath
,
771 if (!EFI_ERROR (Status
)) {
772 Status
= gBS
->OpenProtocol (
774 &gEfiSerialIoProtocolGuid
,
775 (VOID
**) &TerminalDevice
->SerialIo
,
776 This
->DriverBindingHandle
,
777 TerminalDevice
->Handle
,
778 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
780 ASSERT_EFI_ERROR (Status
);
781 StartTerminalStateMachine (TerminalDevice
);
786 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
787 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
788 (EFI_PERIPHERAL_REMOTE_CONSOLE
| EFI_P_EC_CONTROLLER_ERROR
),
793 ASSERT (TerminalDevice
!= NULL
);
795 if (TerminalDevice
->SimpleInput
.WaitForKey
!= NULL
) {
796 gBS
->CloseEvent (TerminalDevice
->SimpleInput
.WaitForKey
);
798 if (TerminalDevice
->SimpleInputEx
.WaitForKeyEx
!= NULL
) {
799 gBS
->CloseEvent (TerminalDevice
->SimpleInputEx
.WaitForKeyEx
);
801 if (TerminalDevice
->KeyNotifyProcessEvent
!= NULL
) {
802 gBS
->CloseEvent (TerminalDevice
->KeyNotifyProcessEvent
);
805 if (TerminalDevice
->RawFiFo
!= NULL
) {
806 FreePool (TerminalDevice
->RawFiFo
);
808 if (TerminalDevice
->UnicodeFiFo
!= NULL
) {
809 FreePool (TerminalDevice
->UnicodeFiFo
);
811 if (TerminalDevice
->EfiKeyFiFo
!= NULL
) {
812 FreePool (TerminalDevice
->EfiKeyFiFo
);
814 if (TerminalDevice
->EfiKeyFiFoForNotify
!= NULL
) {
815 FreePool (TerminalDevice
->EfiKeyFiFoForNotify
);
818 if (TerminalDevice
->ControllerNameTable
!= NULL
) {
819 FreeUnicodeStringTable (TerminalDevice
->ControllerNameTable
);
822 if (TerminalDevice
->DevicePath
!= NULL
) {
823 FreePool (TerminalDevice
->DevicePath
);
826 if (TerminalDevice
->TerminalConsoleModeData
!= NULL
) {
827 FreePool (TerminalDevice
->TerminalConsoleModeData
);
830 FreePool (TerminalDevice
);
835 // Remove Parent Device Path from
836 // the Console Device Environment Variables
838 TerminalRemoveConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME
, ParentDevicePath
);
839 TerminalRemoveConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME
, ParentDevicePath
);
840 TerminalRemoveConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME
, ParentDevicePath
);
842 Status
= gBS
->CloseProtocol (
844 &gEfiSerialIoProtocolGuid
,
845 This
->DriverBindingHandle
,
848 ASSERT_EFI_ERROR (Status
);
850 Status
= gBS
->CloseProtocol (
852 &gEfiDevicePathProtocolGuid
,
853 This
->DriverBindingHandle
,
856 ASSERT_EFI_ERROR (Status
);
861 Stop this driver on Controller by closing Simple Text In, Simple Text
862 In Ex, Simple Text Out protocol, and removing parent device path from
863 Console Device Environment Variables.
865 @param This Protocol instance pointer.
866 @param Controller Handle of device to stop driver on
867 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
868 children is zero stop the entire bus driver.
869 @param ChildHandleBuffer List of Child Handles to Stop.
871 @retval EFI_SUCCESS This driver is removed Controller.
872 @retval other This driver could not be removed from this device.
877 TerminalDriverBindingStop (
878 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
879 IN EFI_HANDLE Controller
,
880 IN UINTN NumberOfChildren
,
881 IN EFI_HANDLE
*ChildHandleBuffer
886 BOOLEAN AllChildrenStopped
;
887 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*SimpleTextOutput
;
888 TERMINAL_DEV
*TerminalDevice
;
889 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
890 EFI_SERIAL_IO_PROTOCOL
*SerialIo
;
893 // Complete all outstanding transactions to Controller.
894 // Don't allow any new transaction to Controller to be started.
896 if (NumberOfChildren
== 0) {
898 // Close the bus driver
900 Status
= gBS
->OpenProtocol (
902 &gEfiDevicePathProtocolGuid
,
903 (VOID
**) &ParentDevicePath
,
904 This
->DriverBindingHandle
,
906 EFI_OPEN_PROTOCOL_GET_PROTOCOL
908 ASSERT_EFI_ERROR (Status
);
911 // Remove Parent Device Path from
912 // the Console Device Environment Variables
914 TerminalRemoveConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME
, ParentDevicePath
);
915 TerminalRemoveConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME
, ParentDevicePath
);
916 TerminalRemoveConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME
, ParentDevicePath
);
920 &gEfiSerialIoProtocolGuid
,
921 This
->DriverBindingHandle
,
927 &gEfiDevicePathProtocolGuid
,
928 This
->DriverBindingHandle
,
935 AllChildrenStopped
= TRUE
;
937 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
939 Status
= gBS
->OpenProtocol (
940 ChildHandleBuffer
[Index
],
941 &gEfiSimpleTextOutProtocolGuid
,
942 (VOID
**) &SimpleTextOutput
,
943 This
->DriverBindingHandle
,
944 ChildHandleBuffer
[Index
],
945 EFI_OPEN_PROTOCOL_GET_PROTOCOL
947 if (!EFI_ERROR (Status
)) {
949 TerminalDevice
= TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput
);
953 &gEfiSerialIoProtocolGuid
,
954 This
->DriverBindingHandle
,
955 ChildHandleBuffer
[Index
]
958 Status
= gBS
->UninstallMultipleProtocolInterfaces (
959 ChildHandleBuffer
[Index
],
960 &gEfiSimpleTextInProtocolGuid
,
961 &TerminalDevice
->SimpleInput
,
962 &gEfiSimpleTextInputExProtocolGuid
,
963 &TerminalDevice
->SimpleInputEx
,
964 &gEfiSimpleTextOutProtocolGuid
,
965 &TerminalDevice
->SimpleTextOutput
,
966 &gEfiDevicePathProtocolGuid
,
967 TerminalDevice
->DevicePath
,
970 if (EFI_ERROR (Status
)) {
973 &gEfiSerialIoProtocolGuid
,
975 This
->DriverBindingHandle
,
976 ChildHandleBuffer
[Index
],
977 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
981 FreeUnicodeStringTable (TerminalDevice
->ControllerNameTable
);
982 StopTerminalStateMachine (TerminalDevice
);
983 gBS
->CloseEvent (TerminalDevice
->SimpleInput
.WaitForKey
);
984 gBS
->CloseEvent (TerminalDevice
->SimpleInputEx
.WaitForKeyEx
);
985 gBS
->CloseEvent (TerminalDevice
->KeyNotifyProcessEvent
);
986 TerminalFreeNotifyList (&TerminalDevice
->NotifyList
);
987 FreePool (TerminalDevice
->DevicePath
);
988 FreePool (TerminalDevice
->TerminalConsoleModeData
);
989 FreePool (TerminalDevice
);
993 if (EFI_ERROR (Status
)) {
994 AllChildrenStopped
= FALSE
;
998 if (!AllChildrenStopped
) {
999 return EFI_DEVICE_ERROR
;
1006 Compare a device path data structure to that of all the nodes of a
1007 second device path instance.
1009 @param Multi A pointer to a multi-instance device path data structure.
1010 @param Single A pointer to a single-instance device path data structure.
1012 @retval TRUE If the Single is contained within Multi.
1013 @retval FALSE The Single is not match within Multi.
1018 IN EFI_DEVICE_PATH_PROTOCOL
*Multi
,
1019 IN EFI_DEVICE_PATH_PROTOCOL
*Single
1022 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1023 EFI_DEVICE_PATH_PROTOCOL
*DevicePathInst
;
1027 DevicePathInst
= GetNextDevicePathInstance (&DevicePath
, &Size
);
1029 // Search for the match of 'Single' in 'Multi'
1031 while (DevicePathInst
!= NULL
) {
1033 // If the single device path is found in multiple device paths,
1036 if (CompareMem (Single
, DevicePathInst
, Size
) == 0) {
1037 FreePool (DevicePathInst
);
1041 FreePool (DevicePathInst
);
1042 DevicePathInst
= GetNextDevicePathInstance (&DevicePath
, &Size
);
1049 Update terminal device path in Console Device Environment Variables.
1051 @param VariableName The Console Device Environment Variable.
1052 @param ParentDevicePath The terminal device path to be updated.
1056 TerminalUpdateConsoleDevVariable (
1057 IN CHAR16
*VariableName
,
1058 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
1064 TERMINAL_TYPE TerminalType
;
1065 EFI_DEVICE_PATH_PROTOCOL
*Variable
;
1066 EFI_DEVICE_PATH_PROTOCOL
*NewVariable
;
1067 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1068 EDKII_SET_VARIABLE_STATUS
*SetVariableStatus
;
1071 // Get global variable and its size according to the name given.
1073 Status
= GetEfiGlobalVariable2 (VariableName
, (VOID
**)&Variable
, NULL
);
1074 if (Status
== EFI_NOT_FOUND
) {
1075 Status
= EFI_SUCCESS
;
1078 if (EFI_ERROR (Status
)) {
1083 // Append terminal device path onto the variable.
1085 for (TerminalType
= 0; TerminalType
< ARRAY_SIZE (mTerminalType
); TerminalType
++) {
1086 SetTerminalDevicePath (TerminalType
, ParentDevicePath
, &TempDevicePath
);
1088 if (TempDevicePath
!= NULL
) {
1089 if (!MatchDevicePaths (Variable
, TempDevicePath
)) {
1090 NewVariable
= AppendDevicePathInstance (Variable
, TempDevicePath
);
1091 if (NewVariable
!= NULL
) {
1092 if (Variable
!= NULL
) {
1093 FreePool (Variable
);
1095 Variable
= NewVariable
;
1099 FreePool (TempDevicePath
);
1104 VariableSize
= GetDevicePathSize (Variable
);
1106 Status
= gRT
->SetVariable (
1108 &gEfiGlobalVariableGuid
,
1109 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1114 if (EFI_ERROR (Status
)) {
1115 NameSize
= StrSize (VariableName
);
1116 SetVariableStatus
= AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS
) + NameSize
+ VariableSize
);
1117 if (SetVariableStatus
!= NULL
) {
1118 CopyGuid (&SetVariableStatus
->Guid
, &gEfiGlobalVariableGuid
);
1119 SetVariableStatus
->NameSize
= NameSize
;
1120 SetVariableStatus
->DataSize
= VariableSize
;
1121 SetVariableStatus
->SetStatus
= Status
;
1122 SetVariableStatus
->Attributes
= EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
;
1123 CopyMem (SetVariableStatus
+ 1, VariableName
, NameSize
);
1124 CopyMem (((UINT8
*) (SetVariableStatus
+ 1)) + NameSize
, Variable
, VariableSize
);
1126 REPORT_STATUS_CODE_EX (
1128 PcdGet32 (PcdErrorCodeSetVariable
),
1131 &gEdkiiStatusCodeDataTypeVariableGuid
,
1133 sizeof (EDKII_SET_VARIABLE_STATUS
) + NameSize
+ VariableSize
1136 FreePool (SetVariableStatus
);
1140 FreePool (Variable
);
1147 Remove terminal device path from Console Device Environment Variables.
1149 @param VariableName Console Device Environment Variables.
1150 @param ParentDevicePath The terminal device path to be updated.
1154 TerminalRemoveConsoleDevVariable (
1155 IN CHAR16
*VariableName
,
1156 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
1164 TERMINAL_TYPE TerminalType
;
1165 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
1166 EFI_DEVICE_PATH_PROTOCOL
*Variable
;
1167 EFI_DEVICE_PATH_PROTOCOL
*OriginalVariable
;
1168 EFI_DEVICE_PATH_PROTOCOL
*NewVariable
;
1169 EFI_DEVICE_PATH_PROTOCOL
*SavedNewVariable
;
1170 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1175 // Get global variable and its size according to the name given.
1177 GetEfiGlobalVariable2 (VariableName
, (VOID
**)&Variable
, NULL
);
1178 if (Variable
== NULL
) {
1183 OriginalVariable
= Variable
;
1187 // Get first device path instance from Variable
1189 Instance
= GetNextDevicePathInstance (&Variable
, &InstanceSize
);
1190 if (Instance
== NULL
) {
1191 FreePool (OriginalVariable
);
1195 // Loop through all the device path instances of Variable
1199 // Loop through all the terminal types that this driver supports
1202 for (TerminalType
= 0; TerminalType
< ARRAY_SIZE (mTerminalType
); TerminalType
++) {
1204 SetTerminalDevicePath (TerminalType
, ParentDevicePath
, &TempDevicePath
);
1207 // Compare the generated device path to the current device path instance
1209 if (TempDevicePath
!= NULL
) {
1210 if (CompareMem (Instance
, TempDevicePath
, InstanceSize
) == 0) {
1215 FreePool (TempDevicePath
);
1219 // If a match was not found, then keep the current device path instance
1222 SavedNewVariable
= NewVariable
;
1223 NewVariable
= AppendDevicePathInstance (NewVariable
, Instance
);
1224 if (SavedNewVariable
!= NULL
) {
1225 FreePool (SavedNewVariable
);
1229 // Get next device path instance from Variable
1231 FreePool (Instance
);
1232 Instance
= GetNextDevicePathInstance (&Variable
, &InstanceSize
);
1233 } while (Instance
!= NULL
);
1235 FreePool (OriginalVariable
);
1238 VariableSize
= GetDevicePathSize (NewVariable
);
1240 Status
= gRT
->SetVariable (
1242 &gEfiGlobalVariableGuid
,
1243 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1248 // Shrinking variable with existing variable driver implementation shouldn't fail.
1250 ASSERT_EFI_ERROR (Status
);
1253 if (NewVariable
!= NULL
) {
1254 FreePool (NewVariable
);
1261 Build terminal device path according to terminal type.
1263 @param TerminalType The terminal type is PC ANSI, VT100, VT100+ or VT-UTF8.
1264 @param ParentDevicePath Parent device path.
1265 @param TerminalDevicePath Returned terminal device path, if building successfully.
1267 @retval EFI_UNSUPPORTED Terminal does not belong to the supported type.
1268 @retval EFI_OUT_OF_RESOURCES Generate terminal device path failed.
1269 @retval EFI_SUCCESS Build terminal device path successfully.
1273 SetTerminalDevicePath (
1274 IN TERMINAL_TYPE TerminalType
,
1275 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
1276 OUT EFI_DEVICE_PATH_PROTOCOL
**TerminalDevicePath
1279 VENDOR_DEVICE_PATH Node
;
1281 ASSERT (TerminalType
< ARRAY_SIZE (mTerminalType
));
1282 Node
.Header
.Type
= MESSAGING_DEVICE_PATH
;
1283 Node
.Header
.SubType
= MSG_VENDOR_DP
;
1284 SetDevicePathNodeLength (&Node
.Header
, sizeof (VENDOR_DEVICE_PATH
));
1285 CopyGuid (&Node
.Guid
, mTerminalType
[TerminalType
]);
1288 // Append the terminal node onto parent device path
1289 // to generate a complete terminal device path.
1291 *TerminalDevicePath
= AppendDevicePathNode (
1293 (EFI_DEVICE_PATH_PROTOCOL
*) &Node
1295 if (*TerminalDevicePath
== NULL
) {
1296 return EFI_OUT_OF_RESOURCES
;
1303 The user Entry Point for module Terminal. The user code starts with this function.
1305 @param ImageHandle The firmware allocated handle for the EFI image.
1306 @param SystemTable A pointer to the EFI System Table.
1308 @retval EFI_SUCCESS The entry point is executed successfully.
1309 @retval other Some error occurs when executing this entry point.
1315 IN EFI_HANDLE ImageHandle
,
1316 IN EFI_SYSTEM_TABLE
*SystemTable
1322 // Install driver model protocol(s).
1324 Status
= EfiLibInstallDriverBindingComponentName2 (
1327 &gTerminalDriverBinding
,
1329 &gTerminalComponentName
,
1330 &gTerminalComponentName2
1332 ASSERT_EFI_ERROR (Status
);
1338 Check if the device supports hot-plug through its device path.
1340 This function could be updated to check more types of Hot Plug devices.
1341 Currently, it checks USB and PCCard device.
1343 @param DevicePath Pointer to device's device path.
1345 @retval TRUE The devcie is a hot-plug device
1346 @retval FALSE The devcie is not a hot-plug device.
1351 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1354 EFI_DEVICE_PATH_PROTOCOL
*CheckDevicePath
;
1356 CheckDevicePath
= DevicePath
;
1357 while (!IsDevicePathEnd (CheckDevicePath
)) {
1359 // Check device whether is hot plug device or not throught Device Path
1361 if ((DevicePathType (CheckDevicePath
) == MESSAGING_DEVICE_PATH
) &&
1362 (DevicePathSubType (CheckDevicePath
) == MSG_USB_DP
||
1363 DevicePathSubType (CheckDevicePath
) == MSG_USB_CLASS_DP
||
1364 DevicePathSubType (CheckDevicePath
) == MSG_USB_WWID_DP
)) {
1366 // If Device is USB device
1370 if ((DevicePathType (CheckDevicePath
) == HARDWARE_DEVICE_PATH
) &&
1371 (DevicePathSubType (CheckDevicePath
) == HW_PCCARD_DP
)) {
1373 // If Device is PCCard
1378 CheckDevicePath
= NextDevicePathNode (CheckDevicePath
);