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
15 EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding
= {
16 TerminalDriverBindingSupported
,
17 TerminalDriverBindingStart
,
18 TerminalDriverBindingStop
,
24 EFI_GUID
*mTerminalType
[] = {
36 CHAR16
*mSerialConsoleNames
[] = {
37 L
"PC-ANSI Serial Console",
38 L
"VT-100 Serial Console",
39 L
"VT-100+ Serial Console",
40 L
"VT-UTF8 Serial Console",
41 L
"Tty Terminal Serial Console",
42 L
"Linux Terminal Serial Console",
43 L
"Xterm R6 Serial Console",
44 L
"VT-400 Serial Console",
45 L
"SCO Terminal Serial Console"
48 TERMINAL_DEV mTerminalDevTemplate
= {
49 TERMINAL_DEV_SIGNATURE
,
56 TerminalConInReadKeyStroke
,
61 TerminalConOutOutputString
,
62 TerminalConOutTestString
,
63 TerminalConOutQueryMode
,
64 TerminalConOutSetMode
,
65 TerminalConOutSetAttribute
,
66 TerminalConOutClearScreen
,
67 TerminalConOutSetCursorPosition
,
68 TerminalConOutEnableCursor
,
71 { // SimpleTextOutputMode
74 EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
), // Attribute
79 NULL
, // TerminalConsoleModeData
85 NULL
, // EfiKeyFiFoForNotify
87 NULL
, // ControllerNameTable
89 NULL
, // TwoSecondTimeOut
99 { // SimpleTextInputEx
100 TerminalConInResetEx
,
101 TerminalConInReadKeyStrokeEx
,
103 TerminalConInSetState
,
104 TerminalConInRegisterKeyNotify
,
105 TerminalConInUnregisterKeyNotify
,
111 NULL
// KeyNotifyProcessEvent
114 TERMINAL_CONSOLE_MODE_DATA mTerminalConsoleModeData
[] = {
119 // New modes can be added here.
124 Convert the GUID representation of terminal type to enum type.
126 @param Guid The GUID representation of terminal type.
128 @return The terminal type in enum type.
131 TerminalTypeFromGuid (
137 for (Type
= 0; Type
< ARRAY_SIZE (mTerminalType
); Type
++) {
138 if (CompareGuid (Guid
, mTerminalType
[Type
])) {
147 Test to see if this driver supports Controller.
149 @param This Protocol instance pointer.
150 @param Controller Handle of device to test
151 @param RemainingDevicePath Optional parameter use to pick a specific child
154 @retval EFI_SUCCESS This driver supports this device.
155 @retval EFI_ALREADY_STARTED This driver is already running on this device.
156 @retval other This driver does not support this device.
161 TerminalDriverBindingSupported (
162 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
163 IN EFI_HANDLE Controller
,
164 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
168 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
169 EFI_SERIAL_IO_PROTOCOL
*SerialIo
;
170 VENDOR_DEVICE_PATH
*Node
;
173 // If remaining device path is not NULL, then make sure it is a
174 // device path that describes a terminal communications protocol.
176 if (RemainingDevicePath
!= NULL
) {
178 // Check if RemainingDevicePath is the End of Device Path Node,
179 // if yes, go on checking other conditions
181 if (!IsDevicePathEnd (RemainingDevicePath
)) {
183 // If RemainingDevicePath isn't the End of Device Path Node,
184 // check its validation
186 Node
= (VENDOR_DEVICE_PATH
*)RemainingDevicePath
;
188 if ((Node
->Header
.Type
!= MESSAGING_DEVICE_PATH
) ||
189 (Node
->Header
.SubType
!= MSG_VENDOR_DP
) ||
190 (DevicePathNodeLength (&Node
->Header
) != sizeof (VENDOR_DEVICE_PATH
)))
192 return EFI_UNSUPPORTED
;
196 // only supports PC ANSI, VT100, VT100+, VT-UTF8, TtyTerm
197 // Linux, XtermR6, VT400 and SCO terminal types
199 if (TerminalTypeFromGuid (&Node
->Guid
) == ARRAY_SIZE (mTerminalType
)) {
200 return EFI_UNSUPPORTED
;
206 // Open the IO Abstraction(s) needed to perform the supported test
207 // The Controller must support the Serial I/O Protocol.
208 // This driver is a bus driver with at most 1 child device, so it is
209 // ok for it to be already started.
211 Status
= gBS
->OpenProtocol (
213 &gEfiSerialIoProtocolGuid
,
215 This
->DriverBindingHandle
,
217 EFI_OPEN_PROTOCOL_BY_DRIVER
219 if (Status
== EFI_ALREADY_STARTED
) {
223 if (EFI_ERROR (Status
)) {
228 // Close the I/O Abstraction(s) used to perform the supported test
232 &gEfiSerialIoProtocolGuid
,
233 This
->DriverBindingHandle
,
238 // Open the EFI Device Path protocol needed to perform the supported test
240 Status
= gBS
->OpenProtocol (
242 &gEfiDevicePathProtocolGuid
,
243 (VOID
**)&ParentDevicePath
,
244 This
->DriverBindingHandle
,
246 EFI_OPEN_PROTOCOL_BY_DRIVER
248 if (Status
== EFI_ALREADY_STARTED
) {
252 if (EFI_ERROR (Status
)) {
257 // Close protocol, don't use device path protocol in the Support() function
261 &gEfiDevicePathProtocolGuid
,
262 This
->DriverBindingHandle
,
270 Free notify functions list.
272 @param ListHead The list head
274 @retval EFI_SUCCESS Free the notify list successfully.
275 @retval EFI_INVALID_PARAMETER ListHead is NULL.
279 TerminalFreeNotifyList (
280 IN OUT LIST_ENTRY
*ListHead
283 TERMINAL_CONSOLE_IN_EX_NOTIFY
*NotifyNode
;
285 if (ListHead
== NULL
) {
286 return EFI_INVALID_PARAMETER
;
289 while (!IsListEmpty (ListHead
)) {
291 ListHead
->ForwardLink
,
292 TERMINAL_CONSOLE_IN_EX_NOTIFY
,
294 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
296 RemoveEntryList (ListHead
->ForwardLink
);
297 FreePool (NotifyNode
);
304 Initialize all the text modes which the terminal console supports.
306 It returns information for available text modes that the terminal can support.
308 @param[out] TextModeCount The total number of text modes that terminal console supports.
310 @return The buffer to the text modes column and row information.
311 Caller is responsible to free it when it's non-NULL.
314 TERMINAL_CONSOLE_MODE_DATA
*
315 InitializeTerminalConsoleTextMode (
316 OUT INT32
*TextModeCount
319 TERMINAL_CONSOLE_MODE_DATA
*TextModeData
;
321 ASSERT (TextModeCount
!= NULL
);
323 TextModeData
= AllocateCopyPool (sizeof (mTerminalConsoleModeData
), mTerminalConsoleModeData
);
324 if (TextModeData
== NULL
) {
328 *TextModeCount
= ARRAY_SIZE (mTerminalConsoleModeData
);
333 for (Index
= 0; Index
< *TextModeCount
; Index
++) {
336 "Terminal - Mode %d, Column = %d, Row = %d\n",
338 TextModeData
[Index
].Columns
,
339 TextModeData
[Index
].Rows
348 Stop the terminal state machine.
350 @param TerminalDevice The terminal device.
353 StopTerminalStateMachine (
354 TERMINAL_DEV
*TerminalDevice
359 OriginalTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
361 gBS
->CloseEvent (TerminalDevice
->TimerEvent
);
362 gBS
->CloseEvent (TerminalDevice
->TwoSecondTimeOut
);
364 gBS
->RestoreTPL (OriginalTpl
);
368 Start the terminal state machine.
370 @param TerminalDevice The terminal device.
373 StartTerminalStateMachine (
374 TERMINAL_DEV
*TerminalDevice
379 Status
= gBS
->CreateEvent (
380 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
382 TerminalConInTimerHandler
,
384 &TerminalDevice
->TimerEvent
386 ASSERT_EFI_ERROR (Status
);
388 Status
= gBS
->SetTimer (
389 TerminalDevice
->TimerEvent
,
391 KEYBOARD_TIMER_INTERVAL
393 ASSERT_EFI_ERROR (Status
);
395 Status
= gBS
->CreateEvent (
400 &TerminalDevice
->TwoSecondTimeOut
402 ASSERT_EFI_ERROR (Status
);
406 Initialize the controller name table.
408 @param TerminalType The terminal type.
409 @param ControllerNameTable The controller name table.
411 @retval EFI_SUCCESS The controller name table is initialized successfully.
412 @retval others Return status of AddUnicodeString2 ().
415 InitializeControllerNameTable (
416 TERMINAL_TYPE TerminalType
,
417 EFI_UNICODE_STRING_TABLE
**ControllerNameTable
421 EFI_UNICODE_STRING_TABLE
*Table
;
423 ASSERT (TerminalType
< ARRAY_SIZE (mTerminalType
));
425 Status
= AddUnicodeString2 (
427 gTerminalComponentName
.SupportedLanguages
,
429 mSerialConsoleNames
[TerminalType
],
432 if (!EFI_ERROR (Status
)) {
433 Status
= AddUnicodeString2 (
435 gTerminalComponentName2
.SupportedLanguages
,
437 mSerialConsoleNames
[TerminalType
],
440 if (EFI_ERROR (Status
)) {
441 FreeUnicodeStringTable (Table
);
445 if (!EFI_ERROR (Status
)) {
446 *ControllerNameTable
= Table
;
453 Start this driver on Controller by opening a Serial IO protocol,
454 reading Device Path, and creating a child handle with a Simple Text In,
455 Simple Text In Ex and Simple Text Out protocol, and device path protocol.
456 And store Console Device Environment Variables.
458 @param This Protocol instance pointer.
459 @param Controller Handle of device to bind driver to
460 @param RemainingDevicePath Optional parameter use to pick a specific child
463 @retval EFI_SUCCESS This driver is added to Controller.
464 @retval EFI_ALREADY_STARTED This driver is already running on Controller.
465 @retval other This driver does not support this device.
470 TerminalDriverBindingStart (
471 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
472 IN EFI_HANDLE Controller
,
473 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
477 EFI_SERIAL_IO_PROTOCOL
*SerialIo
;
478 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
479 EFI_DEVICE_PATH_PROTOCOL
*Vendor
;
480 EFI_HANDLE SerialIoHandle
;
481 EFI_SERIAL_IO_MODE
*Mode
;
482 UINTN SerialInTimeOut
;
483 TERMINAL_DEV
*TerminalDevice
;
485 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
*OpenInfoBuffer
;
488 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*SimpleTextOutput
;
489 EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*SimpleTextInput
;
490 EFI_UNICODE_STRING_TABLE
*ControllerNameTable
;
493 // Get the Device Path Protocol to build the device path of the child device
495 Status
= gBS
->OpenProtocol (
497 &gEfiDevicePathProtocolGuid
,
498 (VOID
**)&ParentDevicePath
,
499 This
->DriverBindingHandle
,
501 EFI_OPEN_PROTOCOL_BY_DRIVER
503 ASSERT ((Status
== EFI_SUCCESS
) || (Status
== EFI_ALREADY_STARTED
));
504 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
509 // Open the Serial I/O Protocol BY_DRIVER. It might already be started.
511 Status
= gBS
->OpenProtocol (
513 &gEfiSerialIoProtocolGuid
,
515 This
->DriverBindingHandle
,
517 EFI_OPEN_PROTOCOL_BY_DRIVER
519 ASSERT ((Status
== EFI_SUCCESS
) || (Status
== EFI_ALREADY_STARTED
));
520 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
524 if (!IsHotPlugDevice (ParentDevicePath
)) {
526 // if the serial device is a hot plug device, do not update the
527 // ConInDev, ConOutDev, and StdErrDev variables.
529 TerminalUpdateConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME
, ParentDevicePath
);
530 TerminalUpdateConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME
, ParentDevicePath
);
531 TerminalUpdateConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME
, ParentDevicePath
);
535 // Do not create any child for END remaining device path.
537 if ((RemainingDevicePath
!= NULL
) && IsDevicePathEnd (RemainingDevicePath
)) {
541 if (Status
== EFI_ALREADY_STARTED
) {
542 if (RemainingDevicePath
== NULL
) {
544 // If RemainingDevicePath is NULL or is the End of Device Path Node
550 // This driver can only produce one child per serial port.
551 // Change its terminal type as remaining device path requests.
553 Status
= gBS
->OpenProtocolInformation (
555 &gEfiSerialIoProtocolGuid
,
559 if (!EFI_ERROR (Status
)) {
560 Status
= EFI_NOT_FOUND
;
561 for (Index
= 0; Index
< EntryCount
; Index
++) {
562 if ((OpenInfoBuffer
[Index
].Attributes
& EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
) != 0) {
563 Status
= gBS
->OpenProtocol (
564 OpenInfoBuffer
[Index
].ControllerHandle
,
565 &gEfiSimpleTextInProtocolGuid
,
566 (VOID
**)&SimpleTextInput
,
567 This
->DriverBindingHandle
,
569 EFI_OPEN_PROTOCOL_GET_PROTOCOL
571 if (!EFI_ERROR (Status
)) {
572 TerminalDevice
= TERMINAL_CON_IN_DEV_FROM_THIS (SimpleTextInput
);
573 TerminalType
= TerminalTypeFromGuid (&((VENDOR_DEVICE_PATH
*)RemainingDevicePath
)->Guid
);
574 ASSERT (TerminalType
< ARRAY_SIZE (mTerminalType
));
575 if (TerminalDevice
->TerminalType
!= TerminalType
) {
576 Status
= InitializeControllerNameTable (TerminalType
, &ControllerNameTable
);
577 if (!EFI_ERROR (Status
)) {
578 StopTerminalStateMachine (TerminalDevice
);
580 // Update the device path
582 Vendor
= TerminalDevice
->DevicePath
;
583 Status
= gBS
->LocateDevicePath (&gEfiSerialIoProtocolGuid
, &Vendor
, &SerialIoHandle
);
584 ASSERT_EFI_ERROR (Status
);
585 CopyGuid (&((VENDOR_DEVICE_PATH
*)Vendor
)->Guid
, mTerminalType
[TerminalType
]);
586 Status
= gBS
->ReinstallProtocolInterface (
587 TerminalDevice
->Handle
,
588 &gEfiDevicePathProtocolGuid
,
589 TerminalDevice
->DevicePath
,
590 TerminalDevice
->DevicePath
592 if (!EFI_ERROR (Status
)) {
593 TerminalDevice
->TerminalType
= TerminalType
;
594 StartTerminalStateMachine (TerminalDevice
);
595 FreeUnicodeStringTable (TerminalDevice
->ControllerNameTable
);
596 TerminalDevice
->ControllerNameTable
= ControllerNameTable
;
599 // Restore the device path on failure
601 CopyGuid (&((VENDOR_DEVICE_PATH
*)Vendor
)->Guid
, mTerminalType
[TerminalDevice
->TerminalType
]);
602 FreeUnicodeStringTable (ControllerNameTable
);
612 FreePool (OpenInfoBuffer
);
619 // Initialize the Terminal Dev
621 TerminalDevice
= AllocateCopyPool (sizeof (TERMINAL_DEV
), &mTerminalDevTemplate
);
622 if (TerminalDevice
== NULL
) {
623 Status
= EFI_OUT_OF_RESOURCES
;
627 if (RemainingDevicePath
== NULL
) {
629 // If RemainingDevicePath is NULL, use default terminal type
631 TerminalDevice
->TerminalType
= PcdGet8 (PcdDefaultTerminalType
);
634 // End of Device Path Node is handled in above.
636 ASSERT (!IsDevicePathEnd (RemainingDevicePath
));
638 // If RemainingDevicePath isn't the End of Device Path Node,
639 // Use the RemainingDevicePath to determine the terminal type
641 TerminalDevice
->TerminalType
= TerminalTypeFromGuid (&((VENDOR_DEVICE_PATH
*)RemainingDevicePath
)->Guid
);
644 ASSERT (TerminalDevice
->TerminalType
< ARRAY_SIZE (mTerminalType
));
645 TerminalDevice
->SerialIo
= SerialIo
;
648 // Build the component name for the child device
650 Status
= InitializeControllerNameTable (TerminalDevice
->TerminalType
, &TerminalDevice
->ControllerNameTable
);
651 if (EFI_ERROR (Status
)) {
656 // Build the device path for the child device
658 Status
= SetTerminalDevicePath (TerminalDevice
->TerminalType
, ParentDevicePath
, &TerminalDevice
->DevicePath
);
659 if (EFI_ERROR (Status
)) {
663 InitializeListHead (&TerminalDevice
->NotifyList
);
664 Status
= gBS
->CreateEvent (
667 TerminalConInWaitForKeyEx
,
669 &TerminalDevice
->SimpleInputEx
.WaitForKeyEx
671 ASSERT_EFI_ERROR (Status
);
673 Status
= gBS
->CreateEvent (
676 TerminalConInWaitForKey
,
678 &TerminalDevice
->SimpleInput
.WaitForKey
680 ASSERT_EFI_ERROR (Status
);
681 Status
= gBS
->CreateEvent (
684 KeyNotifyProcessHandler
,
686 &TerminalDevice
->KeyNotifyProcessEvent
688 ASSERT_EFI_ERROR (Status
);
691 // Allocates and initializes the FIFO buffer to be zero, used for accommodating
692 // the pre-read pending characters.
694 TerminalDevice
->RawFiFo
= AllocateZeroPool (sizeof (RAW_DATA_FIFO
));
695 if (TerminalDevice
->RawFiFo
== NULL
) {
699 TerminalDevice
->UnicodeFiFo
= AllocateZeroPool (sizeof (UNICODE_FIFO
));
700 if (TerminalDevice
->UnicodeFiFo
== NULL
) {
704 TerminalDevice
->EfiKeyFiFo
= AllocateZeroPool (sizeof (EFI_KEY_FIFO
));
705 if (TerminalDevice
->EfiKeyFiFo
== NULL
) {
709 TerminalDevice
->EfiKeyFiFoForNotify
= AllocateZeroPool (sizeof (EFI_KEY_FIFO
));
710 if (TerminalDevice
->EfiKeyFiFoForNotify
== NULL
) {
715 // Set the timeout value of serial buffer for keystroke response performance issue
717 Mode
= TerminalDevice
->SerialIo
->Mode
;
720 if (Mode
->BaudRate
!= 0) {
721 SerialInTimeOut
= (1 + Mode
->DataBits
+ Mode
->StopBits
) * 2 * 1000000 / (UINTN
)Mode
->BaudRate
;
724 Status
= TerminalDevice
->SerialIo
->SetAttributes (
725 TerminalDevice
->SerialIo
,
727 Mode
->ReceiveFifoDepth
,
728 (UINT32
)SerialInTimeOut
,
729 (EFI_PARITY_TYPE
)(Mode
->Parity
),
730 (UINT8
)Mode
->DataBits
,
731 (EFI_STOP_BITS_TYPE
)(Mode
->StopBits
)
733 if (EFI_ERROR (Status
)) {
735 // if set attributes operation fails, invalidate
736 // the value of SerialInTimeOut,thus make it
737 // inconsistent with the default timeout value
738 // of serial buffer. This will invoke the recalculation
739 // in the readkeystroke routine.
741 TerminalDevice
->SerialInTimeOut
= 0;
743 TerminalDevice
->SerialInTimeOut
= SerialInTimeOut
;
746 SimpleTextOutput
= &TerminalDevice
->SimpleTextOutput
;
747 SimpleTextInput
= &TerminalDevice
->SimpleInput
;
750 // Initialize SimpleTextOut instance
752 SimpleTextOutput
->Mode
= &TerminalDevice
->SimpleTextOutputMode
;
753 TerminalDevice
->TerminalConsoleModeData
= InitializeTerminalConsoleTextMode (
754 &SimpleTextOutput
->Mode
->MaxMode
756 if (TerminalDevice
->TerminalConsoleModeData
== NULL
) {
761 // For terminal devices, cursor is always visible
763 SimpleTextOutput
->Mode
->CursorVisible
= TRUE
;
764 Status
= SimpleTextOutput
->SetAttribute (SimpleTextOutput
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
765 if (!EFI_ERROR (Status
)) {
766 Status
= SimpleTextOutput
->Reset (SimpleTextOutput
, FALSE
);
769 if (EFI_ERROR (Status
)) {
774 // Initialize SimpleTextInput instance
776 Status
= SimpleTextInput
->Reset (SimpleTextInput
, FALSE
);
777 if (EFI_ERROR (Status
)) {
781 Status
= gBS
->InstallMultipleProtocolInterfaces (
782 &TerminalDevice
->Handle
,
783 &gEfiSimpleTextInProtocolGuid
,
784 &TerminalDevice
->SimpleInput
,
785 &gEfiSimpleTextInputExProtocolGuid
,
786 &TerminalDevice
->SimpleInputEx
,
787 &gEfiSimpleTextOutProtocolGuid
,
788 &TerminalDevice
->SimpleTextOutput
,
789 &gEfiDevicePathProtocolGuid
,
790 TerminalDevice
->DevicePath
,
793 if (!EFI_ERROR (Status
)) {
794 Status
= gBS
->OpenProtocol (
796 &gEfiSerialIoProtocolGuid
,
797 (VOID
**)&TerminalDevice
->SerialIo
,
798 This
->DriverBindingHandle
,
799 TerminalDevice
->Handle
,
800 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
802 ASSERT_EFI_ERROR (Status
);
803 StartTerminalStateMachine (TerminalDevice
);
808 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
809 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
810 (EFI_PERIPHERAL_REMOTE_CONSOLE
| EFI_P_EC_CONTROLLER_ERROR
),
815 ASSERT (TerminalDevice
!= NULL
);
817 if (TerminalDevice
->SimpleInput
.WaitForKey
!= NULL
) {
818 gBS
->CloseEvent (TerminalDevice
->SimpleInput
.WaitForKey
);
821 if (TerminalDevice
->SimpleInputEx
.WaitForKeyEx
!= NULL
) {
822 gBS
->CloseEvent (TerminalDevice
->SimpleInputEx
.WaitForKeyEx
);
825 if (TerminalDevice
->KeyNotifyProcessEvent
!= NULL
) {
826 gBS
->CloseEvent (TerminalDevice
->KeyNotifyProcessEvent
);
829 if (TerminalDevice
->RawFiFo
!= NULL
) {
830 FreePool (TerminalDevice
->RawFiFo
);
833 if (TerminalDevice
->UnicodeFiFo
!= NULL
) {
834 FreePool (TerminalDevice
->UnicodeFiFo
);
837 if (TerminalDevice
->EfiKeyFiFo
!= NULL
) {
838 FreePool (TerminalDevice
->EfiKeyFiFo
);
841 if (TerminalDevice
->EfiKeyFiFoForNotify
!= NULL
) {
842 FreePool (TerminalDevice
->EfiKeyFiFoForNotify
);
845 if (TerminalDevice
->ControllerNameTable
!= NULL
) {
846 FreeUnicodeStringTable (TerminalDevice
->ControllerNameTable
);
849 if (TerminalDevice
->DevicePath
!= NULL
) {
850 FreePool (TerminalDevice
->DevicePath
);
853 if (TerminalDevice
->TerminalConsoleModeData
!= NULL
) {
854 FreePool (TerminalDevice
->TerminalConsoleModeData
);
857 FreePool (TerminalDevice
);
862 // Remove Parent Device Path from
863 // the Console Device Environment Variables
865 TerminalRemoveConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME
, ParentDevicePath
);
866 TerminalRemoveConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME
, ParentDevicePath
);
867 TerminalRemoveConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME
, ParentDevicePath
);
869 Status
= gBS
->CloseProtocol (
871 &gEfiSerialIoProtocolGuid
,
872 This
->DriverBindingHandle
,
875 ASSERT_EFI_ERROR (Status
);
877 Status
= gBS
->CloseProtocol (
879 &gEfiDevicePathProtocolGuid
,
880 This
->DriverBindingHandle
,
883 ASSERT_EFI_ERROR (Status
);
888 Stop this driver on Controller by closing Simple Text In, Simple Text
889 In Ex, Simple Text Out protocol, and removing parent device path from
890 Console Device Environment Variables.
892 @param This Protocol instance pointer.
893 @param Controller Handle of device to stop driver on
894 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
895 children is zero stop the entire bus driver.
896 @param ChildHandleBuffer List of Child Handles to Stop.
898 @retval EFI_SUCCESS This driver is removed Controller.
899 @retval other This driver could not be removed from this device.
904 TerminalDriverBindingStop (
905 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
906 IN EFI_HANDLE Controller
,
907 IN UINTN NumberOfChildren
,
908 IN EFI_HANDLE
*ChildHandleBuffer
913 BOOLEAN AllChildrenStopped
;
914 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*SimpleTextOutput
;
915 TERMINAL_DEV
*TerminalDevice
;
916 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
917 EFI_SERIAL_IO_PROTOCOL
*SerialIo
;
920 // Complete all outstanding transactions to Controller.
921 // Don't allow any new transaction to Controller to be started.
923 if (NumberOfChildren
== 0) {
925 // Close the bus driver
927 Status
= gBS
->OpenProtocol (
929 &gEfiDevicePathProtocolGuid
,
930 (VOID
**)&ParentDevicePath
,
931 This
->DriverBindingHandle
,
933 EFI_OPEN_PROTOCOL_GET_PROTOCOL
935 ASSERT_EFI_ERROR (Status
);
938 // Remove Parent Device Path from
939 // the Console Device Environment Variables
941 TerminalRemoveConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME
, ParentDevicePath
);
942 TerminalRemoveConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME
, ParentDevicePath
);
943 TerminalRemoveConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME
, ParentDevicePath
);
947 &gEfiSerialIoProtocolGuid
,
948 This
->DriverBindingHandle
,
954 &gEfiDevicePathProtocolGuid
,
955 This
->DriverBindingHandle
,
962 AllChildrenStopped
= TRUE
;
964 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
965 Status
= gBS
->OpenProtocol (
966 ChildHandleBuffer
[Index
],
967 &gEfiSimpleTextOutProtocolGuid
,
968 (VOID
**)&SimpleTextOutput
,
969 This
->DriverBindingHandle
,
970 ChildHandleBuffer
[Index
],
971 EFI_OPEN_PROTOCOL_GET_PROTOCOL
973 if (!EFI_ERROR (Status
)) {
974 TerminalDevice
= TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput
);
978 &gEfiSerialIoProtocolGuid
,
979 This
->DriverBindingHandle
,
980 ChildHandleBuffer
[Index
]
983 Status
= gBS
->UninstallMultipleProtocolInterfaces (
984 ChildHandleBuffer
[Index
],
985 &gEfiSimpleTextInProtocolGuid
,
986 &TerminalDevice
->SimpleInput
,
987 &gEfiSimpleTextInputExProtocolGuid
,
988 &TerminalDevice
->SimpleInputEx
,
989 &gEfiSimpleTextOutProtocolGuid
,
990 &TerminalDevice
->SimpleTextOutput
,
991 &gEfiDevicePathProtocolGuid
,
992 TerminalDevice
->DevicePath
,
995 if (EFI_ERROR (Status
)) {
998 &gEfiSerialIoProtocolGuid
,
1000 This
->DriverBindingHandle
,
1001 ChildHandleBuffer
[Index
],
1002 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1005 FreeUnicodeStringTable (TerminalDevice
->ControllerNameTable
);
1006 StopTerminalStateMachine (TerminalDevice
);
1007 gBS
->CloseEvent (TerminalDevice
->SimpleInput
.WaitForKey
);
1008 gBS
->CloseEvent (TerminalDevice
->SimpleInputEx
.WaitForKeyEx
);
1009 gBS
->CloseEvent (TerminalDevice
->KeyNotifyProcessEvent
);
1010 TerminalFreeNotifyList (&TerminalDevice
->NotifyList
);
1011 FreePool (TerminalDevice
->DevicePath
);
1012 FreePool (TerminalDevice
->TerminalConsoleModeData
);
1013 FreePool (TerminalDevice
);
1017 if (EFI_ERROR (Status
)) {
1018 AllChildrenStopped
= FALSE
;
1022 if (!AllChildrenStopped
) {
1023 return EFI_DEVICE_ERROR
;
1030 Compare a device path data structure to that of all the nodes of a
1031 second device path instance.
1033 @param Multi A pointer to a multi-instance device path data structure.
1034 @param Single A pointer to a single-instance device path data structure.
1036 @retval TRUE If the Single is contained within Multi.
1037 @retval FALSE The Single is not match within Multi.
1042 IN EFI_DEVICE_PATH_PROTOCOL
*Multi
,
1043 IN EFI_DEVICE_PATH_PROTOCOL
*Single
1046 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1047 EFI_DEVICE_PATH_PROTOCOL
*DevicePathInst
;
1051 DevicePathInst
= GetNextDevicePathInstance (&DevicePath
, &Size
);
1053 // Search for the match of 'Single' in 'Multi'
1055 while (DevicePathInst
!= NULL
) {
1057 // If the single device path is found in multiple device paths,
1060 if (CompareMem (Single
, DevicePathInst
, Size
) == 0) {
1061 FreePool (DevicePathInst
);
1065 FreePool (DevicePathInst
);
1066 DevicePathInst
= GetNextDevicePathInstance (&DevicePath
, &Size
);
1073 Update terminal device path in Console Device Environment Variables.
1075 @param VariableName The Console Device Environment Variable.
1076 @param ParentDevicePath The terminal device path to be updated.
1080 TerminalUpdateConsoleDevVariable (
1081 IN CHAR16
*VariableName
,
1082 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
1088 TERMINAL_TYPE TerminalType
;
1089 EFI_DEVICE_PATH_PROTOCOL
*Variable
;
1090 EFI_DEVICE_PATH_PROTOCOL
*NewVariable
;
1091 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1092 EDKII_SET_VARIABLE_STATUS
*SetVariableStatus
;
1095 // Get global variable and its size according to the name given.
1097 Status
= GetEfiGlobalVariable2 (VariableName
, (VOID
**)&Variable
, NULL
);
1098 if (Status
== EFI_NOT_FOUND
) {
1099 Status
= EFI_SUCCESS
;
1103 if (EFI_ERROR (Status
)) {
1108 // Append terminal device path onto the variable.
1110 for (TerminalType
= 0; TerminalType
< ARRAY_SIZE (mTerminalType
); TerminalType
++) {
1111 SetTerminalDevicePath (TerminalType
, ParentDevicePath
, &TempDevicePath
);
1113 if (TempDevicePath
!= NULL
) {
1114 if (!MatchDevicePaths (Variable
, TempDevicePath
)) {
1115 NewVariable
= AppendDevicePathInstance (Variable
, TempDevicePath
);
1116 if (NewVariable
!= NULL
) {
1117 if (Variable
!= NULL
) {
1118 FreePool (Variable
);
1121 Variable
= NewVariable
;
1125 FreePool (TempDevicePath
);
1129 VariableSize
= GetDevicePathSize (Variable
);
1131 Status
= gRT
->SetVariable (
1133 &gEfiGlobalVariableGuid
,
1134 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1139 if (EFI_ERROR (Status
)) {
1140 NameSize
= StrSize (VariableName
);
1141 SetVariableStatus
= AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS
) + NameSize
+ VariableSize
);
1142 if (SetVariableStatus
!= NULL
) {
1143 CopyGuid (&SetVariableStatus
->Guid
, &gEfiGlobalVariableGuid
);
1144 SetVariableStatus
->NameSize
= NameSize
;
1145 SetVariableStatus
->DataSize
= VariableSize
;
1146 SetVariableStatus
->SetStatus
= Status
;
1147 SetVariableStatus
->Attributes
= EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
;
1148 CopyMem (SetVariableStatus
+ 1, VariableName
, NameSize
);
1149 CopyMem (((UINT8
*)(SetVariableStatus
+ 1)) + NameSize
, Variable
, VariableSize
);
1151 REPORT_STATUS_CODE_EX (
1153 PcdGet32 (PcdErrorCodeSetVariable
),
1156 &gEdkiiStatusCodeDataTypeVariableGuid
,
1158 sizeof (EDKII_SET_VARIABLE_STATUS
) + NameSize
+ VariableSize
1161 FreePool (SetVariableStatus
);
1165 FreePool (Variable
);
1171 Remove terminal device path from Console Device Environment Variables.
1173 @param VariableName Console Device Environment Variables.
1174 @param ParentDevicePath The terminal device path to be updated.
1178 TerminalRemoveConsoleDevVariable (
1179 IN CHAR16
*VariableName
,
1180 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
1188 TERMINAL_TYPE TerminalType
;
1189 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
1190 EFI_DEVICE_PATH_PROTOCOL
*Variable
;
1191 EFI_DEVICE_PATH_PROTOCOL
*OriginalVariable
;
1192 EFI_DEVICE_PATH_PROTOCOL
*NewVariable
;
1193 EFI_DEVICE_PATH_PROTOCOL
*SavedNewVariable
;
1194 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1199 // Get global variable and its size according to the name given.
1201 GetEfiGlobalVariable2 (VariableName
, (VOID
**)&Variable
, NULL
);
1202 if (Variable
== NULL
) {
1207 OriginalVariable
= Variable
;
1211 // Get first device path instance from Variable
1213 Instance
= GetNextDevicePathInstance (&Variable
, &InstanceSize
);
1214 if (Instance
== NULL
) {
1215 FreePool (OriginalVariable
);
1220 // Loop through all the device path instances of Variable
1224 // Loop through all the terminal types that this driver supports
1227 for (TerminalType
= 0; TerminalType
< ARRAY_SIZE (mTerminalType
); TerminalType
++) {
1228 SetTerminalDevicePath (TerminalType
, ParentDevicePath
, &TempDevicePath
);
1231 // Compare the generated device path to the current device path instance
1233 if (TempDevicePath
!= NULL
) {
1234 if (CompareMem (Instance
, TempDevicePath
, InstanceSize
) == 0) {
1239 FreePool (TempDevicePath
);
1244 // If a match was not found, then keep the current device path instance
1247 SavedNewVariable
= NewVariable
;
1248 NewVariable
= AppendDevicePathInstance (NewVariable
, Instance
);
1249 if (SavedNewVariable
!= NULL
) {
1250 FreePool (SavedNewVariable
);
1255 // Get next device path instance from Variable
1257 FreePool (Instance
);
1258 Instance
= GetNextDevicePathInstance (&Variable
, &InstanceSize
);
1259 } while (Instance
!= NULL
);
1261 FreePool (OriginalVariable
);
1264 VariableSize
= GetDevicePathSize (NewVariable
);
1266 Status
= gRT
->SetVariable (
1268 &gEfiGlobalVariableGuid
,
1269 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1274 // Shrinking variable with existing variable driver implementation shouldn't fail.
1276 ASSERT_EFI_ERROR (Status
);
1279 if (NewVariable
!= NULL
) {
1280 FreePool (NewVariable
);
1287 Build terminal device path according to terminal type.
1289 @param TerminalType The terminal type is PC ANSI, VT100, VT100+ or VT-UTF8.
1290 @param ParentDevicePath Parent device path.
1291 @param TerminalDevicePath Returned terminal device path, if building successfully.
1293 @retval EFI_UNSUPPORTED Terminal does not belong to the supported type.
1294 @retval EFI_OUT_OF_RESOURCES Generate terminal device path failed.
1295 @retval EFI_SUCCESS Build terminal device path successfully.
1299 SetTerminalDevicePath (
1300 IN TERMINAL_TYPE TerminalType
,
1301 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
1302 OUT EFI_DEVICE_PATH_PROTOCOL
**TerminalDevicePath
1305 VENDOR_DEVICE_PATH Node
;
1307 ASSERT (TerminalType
< ARRAY_SIZE (mTerminalType
));
1308 Node
.Header
.Type
= MESSAGING_DEVICE_PATH
;
1309 Node
.Header
.SubType
= MSG_VENDOR_DP
;
1310 SetDevicePathNodeLength (&Node
.Header
, sizeof (VENDOR_DEVICE_PATH
));
1311 CopyGuid (&Node
.Guid
, mTerminalType
[TerminalType
]);
1314 // Append the terminal node onto parent device path
1315 // to generate a complete terminal device path.
1317 *TerminalDevicePath
= AppendDevicePathNode (
1319 (EFI_DEVICE_PATH_PROTOCOL
*)&Node
1321 if (*TerminalDevicePath
== NULL
) {
1322 return EFI_OUT_OF_RESOURCES
;
1329 The user Entry Point for module Terminal. The user code starts with this function.
1331 @param ImageHandle The firmware allocated handle for the EFI image.
1332 @param SystemTable A pointer to the EFI System Table.
1334 @retval EFI_SUCCESS The entry point is executed successfully.
1335 @retval other Some error occurs when executing this entry point.
1340 InitializeTerminal (
1341 IN EFI_HANDLE ImageHandle
,
1342 IN EFI_SYSTEM_TABLE
*SystemTable
1348 // Install driver model protocol(s).
1350 Status
= EfiLibInstallDriverBindingComponentName2 (
1353 &gTerminalDriverBinding
,
1355 &gTerminalComponentName
,
1356 &gTerminalComponentName2
1358 ASSERT_EFI_ERROR (Status
);
1364 Check if the device supports hot-plug through its device path.
1366 This function could be updated to check more types of Hot Plug devices.
1367 Currently, it checks USB and PCCard device.
1369 @param DevicePath Pointer to device's device path.
1371 @retval TRUE The devcie is a hot-plug device
1372 @retval FALSE The devcie is not a hot-plug device.
1377 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1380 EFI_DEVICE_PATH_PROTOCOL
*CheckDevicePath
;
1382 CheckDevicePath
= DevicePath
;
1383 while (!IsDevicePathEnd (CheckDevicePath
)) {
1385 // Check device whether is hot plug device or not throught Device Path
1387 if ((DevicePathType (CheckDevicePath
) == MESSAGING_DEVICE_PATH
) &&
1388 ((DevicePathSubType (CheckDevicePath
) == MSG_USB_DP
) ||
1389 (DevicePathSubType (CheckDevicePath
) == MSG_USB_CLASS_DP
) ||
1390 (DevicePathSubType (CheckDevicePath
) == MSG_USB_WWID_DP
)))
1393 // If Device is USB device
1398 if ((DevicePathType (CheckDevicePath
) == HARDWARE_DEVICE_PATH
) &&
1399 (DevicePathSubType (CheckDevicePath
) == HW_PCCARD_DP
))
1402 // If Device is PCCard
1407 CheckDevicePath
= NextDevicePathNode (CheckDevicePath
);