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 - 2018, 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
[] = {
35 CHAR16
*mSerialConsoleNames
[] = {
36 L
"PC-ANSI Serial Console",
37 L
"VT-100 Serial Console",
38 L
"VT-100+ Serial Console",
39 L
"VT-UTF8 Serial Console",
40 L
"Tty Terminal Serial Console"
43 TERMINAL_DEV mTerminalDevTemplate
= {
44 TERMINAL_DEV_SIGNATURE
,
51 TerminalConInReadKeyStroke
,
56 TerminalConOutOutputString
,
57 TerminalConOutTestString
,
58 TerminalConOutQueryMode
,
59 TerminalConOutSetMode
,
60 TerminalConOutSetAttribute
,
61 TerminalConOutClearScreen
,
62 TerminalConOutSetCursorPosition
,
63 TerminalConOutEnableCursor
,
66 { // SimpleTextOutputMode
69 EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
), // Attribute
74 NULL
, // TerminalConsoleModeData
80 NULL
, // EfiKeyFiFoForNotify
82 NULL
, // ControllerNameTable
84 NULL
, // TwoSecondTimeOut
94 { // SimpleTextInputEx
96 TerminalConInReadKeyStrokeEx
,
98 TerminalConInSetState
,
99 TerminalConInRegisterKeyNotify
,
100 TerminalConInUnregisterKeyNotify
,
106 NULL
// KeyNotifyProcessEvent
109 TERMINAL_CONSOLE_MODE_DATA mTerminalConsoleModeData
[] = {
114 // New modes can be added here.
119 Convert the GUID representation of terminal type to enum type.
121 @param Guid The GUID representation of terminal type.
123 @return The terminal type in enum type.
126 TerminalTypeFromGuid (
132 for (Type
= 0; Type
< ARRAY_SIZE (mTerminalType
); Type
++) {
133 if (CompareGuid (Guid
, mTerminalType
[Type
])) {
141 Test to see if this driver supports Controller.
143 @param This Protocol instance pointer.
144 @param Controller Handle of device to test
145 @param RemainingDevicePath Optional parameter use to pick a specific child
148 @retval EFI_SUCCESS This driver supports this device.
149 @retval EFI_ALREADY_STARTED This driver is already running on this device.
150 @retval other This driver does not support this device.
155 TerminalDriverBindingSupported (
156 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
157 IN EFI_HANDLE Controller
,
158 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
162 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
163 EFI_SERIAL_IO_PROTOCOL
*SerialIo
;
164 VENDOR_DEVICE_PATH
*Node
;
167 // If remaining device path is not NULL, then make sure it is a
168 // device path that describes a terminal communications protocol.
170 if (RemainingDevicePath
!= NULL
) {
172 // Check if RemainingDevicePath is the End of Device Path Node,
173 // if yes, go on checking other conditions
175 if (!IsDevicePathEnd (RemainingDevicePath
)) {
177 // If RemainingDevicePath isn't the End of Device Path Node,
178 // check its validation
180 Node
= (VENDOR_DEVICE_PATH
*) RemainingDevicePath
;
182 if (Node
->Header
.Type
!= MESSAGING_DEVICE_PATH
||
183 Node
->Header
.SubType
!= MSG_VENDOR_DP
||
184 DevicePathNodeLength(&Node
->Header
) != sizeof(VENDOR_DEVICE_PATH
)) {
186 return EFI_UNSUPPORTED
;
190 // only supports PC ANSI, VT100, VT100+, VT-UTF8, and TtyTerm terminal types
192 if (TerminalTypeFromGuid (&Node
->Guid
) == ARRAY_SIZE (mTerminalType
)) {
193 return EFI_UNSUPPORTED
;
198 // Open the IO Abstraction(s) needed to perform the supported test
199 // The Controller must support the Serial I/O Protocol.
200 // This driver is a bus driver with at most 1 child device, so it is
201 // ok for it to be already started.
203 Status
= gBS
->OpenProtocol (
205 &gEfiSerialIoProtocolGuid
,
207 This
->DriverBindingHandle
,
209 EFI_OPEN_PROTOCOL_BY_DRIVER
211 if (Status
== EFI_ALREADY_STARTED
) {
215 if (EFI_ERROR (Status
)) {
220 // Close the I/O Abstraction(s) used to perform the supported test
224 &gEfiSerialIoProtocolGuid
,
225 This
->DriverBindingHandle
,
230 // Open the EFI Device Path protocol needed to perform the supported test
232 Status
= gBS
->OpenProtocol (
234 &gEfiDevicePathProtocolGuid
,
235 (VOID
**) &ParentDevicePath
,
236 This
->DriverBindingHandle
,
238 EFI_OPEN_PROTOCOL_BY_DRIVER
240 if (Status
== EFI_ALREADY_STARTED
) {
244 if (EFI_ERROR (Status
)) {
249 // Close protocol, don't use device path protocol in the Support() function
253 &gEfiDevicePathProtocolGuid
,
254 This
->DriverBindingHandle
,
263 Free notify functions list.
265 @param ListHead The list head
267 @retval EFI_SUCCESS Free the notify list successfully.
268 @retval EFI_INVALID_PARAMETER ListHead is NULL.
272 TerminalFreeNotifyList (
273 IN OUT LIST_ENTRY
*ListHead
276 TERMINAL_CONSOLE_IN_EX_NOTIFY
*NotifyNode
;
278 if (ListHead
== NULL
) {
279 return EFI_INVALID_PARAMETER
;
281 while (!IsListEmpty (ListHead
)) {
283 ListHead
->ForwardLink
,
284 TERMINAL_CONSOLE_IN_EX_NOTIFY
,
286 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
288 RemoveEntryList (ListHead
->ForwardLink
);
289 FreePool (NotifyNode
);
296 Initialize all the text modes which the terminal console supports.
298 It returns information for available text modes that the terminal can support.
300 @param[out] TextModeCount The total number of text modes that terminal console supports.
302 @return The buffer to the text modes column and row information.
303 Caller is responsible to free it when it's non-NULL.
306 TERMINAL_CONSOLE_MODE_DATA
*
307 InitializeTerminalConsoleTextMode (
308 OUT INT32
*TextModeCount
311 TERMINAL_CONSOLE_MODE_DATA
*TextModeData
;
313 ASSERT (TextModeCount
!= NULL
);
315 TextModeData
= AllocateCopyPool (sizeof (mTerminalConsoleModeData
), mTerminalConsoleModeData
);
316 if (TextModeData
== NULL
) {
319 *TextModeCount
= ARRAY_SIZE (mTerminalConsoleModeData
);
323 for (Index
= 0; Index
< *TextModeCount
; Index
++) {
324 DEBUG ((DEBUG_INFO
, "Terminal - Mode %d, Column = %d, Row = %d\n",
325 Index
, TextModeData
[Index
].Columns
, TextModeData
[Index
].Rows
));
332 Stop the terminal state machine.
334 @param TerminalDevice The terminal device.
337 StopTerminalStateMachine (
338 TERMINAL_DEV
*TerminalDevice
343 OriginalTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
345 gBS
->CloseEvent (TerminalDevice
->TimerEvent
);
346 gBS
->CloseEvent (TerminalDevice
->TwoSecondTimeOut
);
348 gBS
->RestoreTPL (OriginalTpl
);
352 Start the terminal state machine.
354 @param TerminalDevice The terminal device.
357 StartTerminalStateMachine (
358 TERMINAL_DEV
*TerminalDevice
362 Status
= gBS
->CreateEvent (
363 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
365 TerminalConInTimerHandler
,
367 &TerminalDevice
->TimerEvent
369 ASSERT_EFI_ERROR (Status
);
371 Status
= gBS
->SetTimer (
372 TerminalDevice
->TimerEvent
,
374 KEYBOARD_TIMER_INTERVAL
376 ASSERT_EFI_ERROR (Status
);
378 Status
= gBS
->CreateEvent (
383 &TerminalDevice
->TwoSecondTimeOut
385 ASSERT_EFI_ERROR (Status
);
389 Initialize the controller name table.
391 @param TerminalType The terminal type.
392 @param ControllerNameTable The controller name table.
394 @retval EFI_SUCCESS The controller name table is initialized successfully.
395 @retval others Return status of AddUnicodeString2 ().
398 InitializeControllerNameTable (
399 TERMINAL_TYPE TerminalType
,
400 EFI_UNICODE_STRING_TABLE
**ControllerNameTable
404 EFI_UNICODE_STRING_TABLE
*Table
;
406 ASSERT (TerminalType
< ARRAY_SIZE (mTerminalType
));
408 Status
= AddUnicodeString2 (
410 gTerminalComponentName
.SupportedLanguages
,
412 mSerialConsoleNames
[TerminalType
],
415 if (!EFI_ERROR (Status
)) {
416 Status
= AddUnicodeString2 (
418 gTerminalComponentName2
.SupportedLanguages
,
420 mSerialConsoleNames
[TerminalType
],
423 if (EFI_ERROR (Status
)) {
424 FreeUnicodeStringTable (Table
);
427 if (!EFI_ERROR (Status
)) {
428 *ControllerNameTable
= Table
;
434 Start this driver on Controller by opening a Serial IO protocol,
435 reading Device Path, and creating a child handle with a Simple Text In,
436 Simple Text In Ex and Simple Text Out protocol, and device path protocol.
437 And store Console Device Environment Variables.
439 @param This Protocol instance pointer.
440 @param Controller Handle of device to bind driver to
441 @param RemainingDevicePath Optional parameter use to pick a specific child
444 @retval EFI_SUCCESS This driver is added to Controller.
445 @retval EFI_ALREADY_STARTED This driver is already running on Controller.
446 @retval other This driver does not support this device.
451 TerminalDriverBindingStart (
452 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
453 IN EFI_HANDLE Controller
,
454 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
458 EFI_SERIAL_IO_PROTOCOL
*SerialIo
;
459 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
460 EFI_DEVICE_PATH_PROTOCOL
*Vendor
;
461 EFI_HANDLE SerialIoHandle
;
462 EFI_SERIAL_IO_MODE
*Mode
;
463 UINTN SerialInTimeOut
;
464 TERMINAL_DEV
*TerminalDevice
;
466 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
*OpenInfoBuffer
;
469 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*SimpleTextOutput
;
470 EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*SimpleTextInput
;
471 EFI_UNICODE_STRING_TABLE
*ControllerNameTable
;
474 // Get the Device Path Protocol to build the device path of the child device
476 Status
= gBS
->OpenProtocol (
478 &gEfiDevicePathProtocolGuid
,
479 (VOID
**) &ParentDevicePath
,
480 This
->DriverBindingHandle
,
482 EFI_OPEN_PROTOCOL_BY_DRIVER
484 ASSERT ((Status
== EFI_SUCCESS
) || (Status
== EFI_ALREADY_STARTED
));
485 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
490 // Open the Serial I/O Protocol BY_DRIVER. It might already be started.
492 Status
= gBS
->OpenProtocol (
494 &gEfiSerialIoProtocolGuid
,
496 This
->DriverBindingHandle
,
498 EFI_OPEN_PROTOCOL_BY_DRIVER
500 ASSERT ((Status
== EFI_SUCCESS
) || (Status
== EFI_ALREADY_STARTED
));
501 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
505 if (!IsHotPlugDevice (ParentDevicePath
)) {
507 // if the serial device is a hot plug device, do not update the
508 // ConInDev, ConOutDev, and StdErrDev variables.
510 TerminalUpdateConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME
, ParentDevicePath
);
511 TerminalUpdateConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME
, ParentDevicePath
);
512 TerminalUpdateConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME
, ParentDevicePath
);
516 // Do not create any child for END remaining device path.
518 if ((RemainingDevicePath
!= NULL
) && IsDevicePathEnd (RemainingDevicePath
)) {
522 if (Status
== EFI_ALREADY_STARTED
) {
524 if (RemainingDevicePath
== NULL
) {
526 // If RemainingDevicePath is NULL or is the End of Device Path Node
532 // This driver can only produce one child per serial port.
533 // Change its terminal type as remaining device path requests.
535 Status
= gBS
->OpenProtocolInformation (
537 &gEfiSerialIoProtocolGuid
,
541 if (!EFI_ERROR (Status
)) {
542 Status
= EFI_NOT_FOUND
;
543 for (Index
= 0; Index
< EntryCount
; Index
++) {
544 if ((OpenInfoBuffer
[Index
].Attributes
& EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
) != 0) {
545 Status
= gBS
->OpenProtocol (
546 OpenInfoBuffer
[Index
].ControllerHandle
,
547 &gEfiSimpleTextInProtocolGuid
,
548 (VOID
**) &SimpleTextInput
,
549 This
->DriverBindingHandle
,
551 EFI_OPEN_PROTOCOL_GET_PROTOCOL
553 if (!EFI_ERROR (Status
)) {
554 TerminalDevice
= TERMINAL_CON_IN_DEV_FROM_THIS (SimpleTextInput
);
555 TerminalType
= TerminalTypeFromGuid (&((VENDOR_DEVICE_PATH
*) RemainingDevicePath
)->Guid
);
556 ASSERT (TerminalType
< ARRAY_SIZE (mTerminalType
));
557 if (TerminalDevice
->TerminalType
!= TerminalType
) {
558 Status
= InitializeControllerNameTable (TerminalType
, &ControllerNameTable
);
559 if (!EFI_ERROR (Status
)) {
560 StopTerminalStateMachine (TerminalDevice
);
562 // Update the device path
564 Vendor
= TerminalDevice
->DevicePath
;
565 Status
= gBS
->LocateDevicePath (&gEfiSerialIoProtocolGuid
, &Vendor
, &SerialIoHandle
);
566 ASSERT_EFI_ERROR (Status
);
567 CopyGuid (&((VENDOR_DEVICE_PATH
*) Vendor
)->Guid
, mTerminalType
[TerminalType
]);
568 Status
= gBS
->ReinstallProtocolInterface (
569 TerminalDevice
->Handle
,
570 &gEfiDevicePathProtocolGuid
,
571 TerminalDevice
->DevicePath
,
572 TerminalDevice
->DevicePath
574 if (!EFI_ERROR (Status
)) {
575 TerminalDevice
->TerminalType
= TerminalType
;
576 StartTerminalStateMachine (TerminalDevice
);
577 FreeUnicodeStringTable (TerminalDevice
->ControllerNameTable
);
578 TerminalDevice
->ControllerNameTable
= ControllerNameTable
;
581 // Restore the device path on failure
583 CopyGuid (&((VENDOR_DEVICE_PATH
*) Vendor
)->Guid
, mTerminalType
[TerminalDevice
->TerminalType
]);
584 FreeUnicodeStringTable (ControllerNameTable
);
592 FreePool (OpenInfoBuffer
);
598 // Initialize the Terminal Dev
600 TerminalDevice
= AllocateCopyPool (sizeof (TERMINAL_DEV
), &mTerminalDevTemplate
);
601 if (TerminalDevice
== NULL
) {
602 Status
= EFI_OUT_OF_RESOURCES
;
606 if (RemainingDevicePath
== NULL
) {
608 // If RemainingDevicePath is NULL, use default terminal type
610 TerminalDevice
->TerminalType
= PcdGet8 (PcdDefaultTerminalType
);
613 // End of Device Path Node is handled in above.
615 ASSERT (!IsDevicePathEnd (RemainingDevicePath
));
617 // If RemainingDevicePath isn't the End of Device Path Node,
618 // Use the RemainingDevicePath to determine the terminal type
620 TerminalDevice
->TerminalType
= TerminalTypeFromGuid (&((VENDOR_DEVICE_PATH
*) RemainingDevicePath
)->Guid
);
622 ASSERT (TerminalDevice
->TerminalType
< ARRAY_SIZE (mTerminalType
));
623 TerminalDevice
->SerialIo
= SerialIo
;
626 // Build the component name for the child device
628 Status
= InitializeControllerNameTable (TerminalDevice
->TerminalType
, &TerminalDevice
->ControllerNameTable
);
629 if (EFI_ERROR (Status
)) {
634 // Build the device path for the child device
636 Status
= SetTerminalDevicePath (TerminalDevice
->TerminalType
, ParentDevicePath
, &TerminalDevice
->DevicePath
);
637 if (EFI_ERROR (Status
)) {
641 InitializeListHead (&TerminalDevice
->NotifyList
);
642 Status
= gBS
->CreateEvent (
645 TerminalConInWaitForKeyEx
,
647 &TerminalDevice
->SimpleInputEx
.WaitForKeyEx
649 ASSERT_EFI_ERROR (Status
);
651 Status
= gBS
->CreateEvent (
654 TerminalConInWaitForKey
,
656 &TerminalDevice
->SimpleInput
.WaitForKey
658 ASSERT_EFI_ERROR (Status
);
659 Status
= gBS
->CreateEvent (
662 KeyNotifyProcessHandler
,
664 &TerminalDevice
->KeyNotifyProcessEvent
666 ASSERT_EFI_ERROR (Status
);
669 // Allocates and initializes the FIFO buffer to be zero, used for accommodating
670 // the pre-read pending characters.
672 TerminalDevice
->RawFiFo
= AllocateZeroPool (sizeof (RAW_DATA_FIFO
));
673 if (TerminalDevice
->RawFiFo
== NULL
) {
676 TerminalDevice
->UnicodeFiFo
= AllocateZeroPool (sizeof (UNICODE_FIFO
));
677 if (TerminalDevice
->UnicodeFiFo
== NULL
) {
680 TerminalDevice
->EfiKeyFiFo
= AllocateZeroPool (sizeof (EFI_KEY_FIFO
));
681 if (TerminalDevice
->EfiKeyFiFo
== NULL
) {
684 TerminalDevice
->EfiKeyFiFoForNotify
= AllocateZeroPool (sizeof (EFI_KEY_FIFO
));
685 if (TerminalDevice
->EfiKeyFiFoForNotify
== NULL
) {
690 // Set the timeout value of serial buffer for keystroke response performance issue
692 Mode
= TerminalDevice
->SerialIo
->Mode
;
695 if (Mode
->BaudRate
!= 0) {
696 SerialInTimeOut
= (1 + Mode
->DataBits
+ Mode
->StopBits
) * 2 * 1000000 / (UINTN
) Mode
->BaudRate
;
699 Status
= TerminalDevice
->SerialIo
->SetAttributes (
700 TerminalDevice
->SerialIo
,
702 Mode
->ReceiveFifoDepth
,
703 (UINT32
) SerialInTimeOut
,
704 (EFI_PARITY_TYPE
) (Mode
->Parity
),
705 (UINT8
) Mode
->DataBits
,
706 (EFI_STOP_BITS_TYPE
) (Mode
->StopBits
)
708 if (EFI_ERROR (Status
)) {
710 // if set attributes operation fails, invalidate
711 // the value of SerialInTimeOut,thus make it
712 // inconsistent with the default timeout value
713 // of serial buffer. This will invoke the recalculation
714 // in the readkeystroke routine.
716 TerminalDevice
->SerialInTimeOut
= 0;
718 TerminalDevice
->SerialInTimeOut
= SerialInTimeOut
;
721 SimpleTextOutput
= &TerminalDevice
->SimpleTextOutput
;
722 SimpleTextInput
= &TerminalDevice
->SimpleInput
;
725 // Initialize SimpleTextOut instance
727 SimpleTextOutput
->Mode
= &TerminalDevice
->SimpleTextOutputMode
;
728 TerminalDevice
->TerminalConsoleModeData
= InitializeTerminalConsoleTextMode (
729 &SimpleTextOutput
->Mode
->MaxMode
731 if (TerminalDevice
->TerminalConsoleModeData
== NULL
) {
735 // For terminal devices, cursor is always visible
737 SimpleTextOutput
->Mode
->CursorVisible
= TRUE
;
738 Status
= SimpleTextOutput
->SetAttribute (SimpleTextOutput
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
739 if (!EFI_ERROR (Status
)) {
740 Status
= SimpleTextOutput
->Reset (SimpleTextOutput
, FALSE
);
742 if (EFI_ERROR (Status
)) {
747 // Initialize SimpleTextInput instance
749 Status
= SimpleTextInput
->Reset (SimpleTextInput
, FALSE
);
750 if (EFI_ERROR (Status
)) {
754 Status
= gBS
->InstallMultipleProtocolInterfaces (
755 &TerminalDevice
->Handle
,
756 &gEfiSimpleTextInProtocolGuid
, &TerminalDevice
->SimpleInput
,
757 &gEfiSimpleTextInputExProtocolGuid
, &TerminalDevice
->SimpleInputEx
,
758 &gEfiSimpleTextOutProtocolGuid
, &TerminalDevice
->SimpleTextOutput
,
759 &gEfiDevicePathProtocolGuid
, TerminalDevice
->DevicePath
,
762 if (!EFI_ERROR (Status
)) {
763 Status
= gBS
->OpenProtocol (
765 &gEfiSerialIoProtocolGuid
,
766 (VOID
**) &TerminalDevice
->SerialIo
,
767 This
->DriverBindingHandle
,
768 TerminalDevice
->Handle
,
769 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
771 ASSERT_EFI_ERROR (Status
);
772 StartTerminalStateMachine (TerminalDevice
);
777 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
778 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
779 (EFI_PERIPHERAL_REMOTE_CONSOLE
| EFI_P_EC_CONTROLLER_ERROR
),
784 ASSERT (TerminalDevice
!= NULL
);
786 if (TerminalDevice
->SimpleInput
.WaitForKey
!= NULL
) {
787 gBS
->CloseEvent (TerminalDevice
->SimpleInput
.WaitForKey
);
789 if (TerminalDevice
->SimpleInputEx
.WaitForKeyEx
!= NULL
) {
790 gBS
->CloseEvent (TerminalDevice
->SimpleInputEx
.WaitForKeyEx
);
792 if (TerminalDevice
->KeyNotifyProcessEvent
!= NULL
) {
793 gBS
->CloseEvent (TerminalDevice
->KeyNotifyProcessEvent
);
796 if (TerminalDevice
->RawFiFo
!= NULL
) {
797 FreePool (TerminalDevice
->RawFiFo
);
799 if (TerminalDevice
->UnicodeFiFo
!= NULL
) {
800 FreePool (TerminalDevice
->UnicodeFiFo
);
802 if (TerminalDevice
->EfiKeyFiFo
!= NULL
) {
803 FreePool (TerminalDevice
->EfiKeyFiFo
);
805 if (TerminalDevice
->EfiKeyFiFoForNotify
!= NULL
) {
806 FreePool (TerminalDevice
->EfiKeyFiFoForNotify
);
809 if (TerminalDevice
->ControllerNameTable
!= NULL
) {
810 FreeUnicodeStringTable (TerminalDevice
->ControllerNameTable
);
813 if (TerminalDevice
->DevicePath
!= NULL
) {
814 FreePool (TerminalDevice
->DevicePath
);
817 if (TerminalDevice
->TerminalConsoleModeData
!= NULL
) {
818 FreePool (TerminalDevice
->TerminalConsoleModeData
);
821 FreePool (TerminalDevice
);
826 // Remove Parent Device Path from
827 // the Console Device Environment Variables
829 TerminalRemoveConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME
, ParentDevicePath
);
830 TerminalRemoveConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME
, ParentDevicePath
);
831 TerminalRemoveConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME
, ParentDevicePath
);
833 Status
= gBS
->CloseProtocol (
835 &gEfiSerialIoProtocolGuid
,
836 This
->DriverBindingHandle
,
839 ASSERT_EFI_ERROR (Status
);
841 Status
= gBS
->CloseProtocol (
843 &gEfiDevicePathProtocolGuid
,
844 This
->DriverBindingHandle
,
847 ASSERT_EFI_ERROR (Status
);
852 Stop this driver on Controller by closing Simple Text In, Simple Text
853 In Ex, Simple Text Out protocol, and removing parent device path from
854 Console Device Environment Variables.
856 @param This Protocol instance pointer.
857 @param Controller Handle of device to stop driver on
858 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
859 children is zero stop the entire bus driver.
860 @param ChildHandleBuffer List of Child Handles to Stop.
862 @retval EFI_SUCCESS This driver is removed Controller.
863 @retval other This driver could not be removed from this device.
868 TerminalDriverBindingStop (
869 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
870 IN EFI_HANDLE Controller
,
871 IN UINTN NumberOfChildren
,
872 IN EFI_HANDLE
*ChildHandleBuffer
877 BOOLEAN AllChildrenStopped
;
878 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*SimpleTextOutput
;
879 TERMINAL_DEV
*TerminalDevice
;
880 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
881 EFI_SERIAL_IO_PROTOCOL
*SerialIo
;
884 // Complete all outstanding transactions to Controller.
885 // Don't allow any new transaction to Controller to be started.
887 if (NumberOfChildren
== 0) {
889 // Close the bus driver
891 Status
= gBS
->OpenProtocol (
893 &gEfiDevicePathProtocolGuid
,
894 (VOID
**) &ParentDevicePath
,
895 This
->DriverBindingHandle
,
897 EFI_OPEN_PROTOCOL_GET_PROTOCOL
899 ASSERT_EFI_ERROR (Status
);
902 // Remove Parent Device Path from
903 // the Console Device Environment Variables
905 TerminalRemoveConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME
, ParentDevicePath
);
906 TerminalRemoveConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME
, ParentDevicePath
);
907 TerminalRemoveConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME
, ParentDevicePath
);
911 &gEfiSerialIoProtocolGuid
,
912 This
->DriverBindingHandle
,
918 &gEfiDevicePathProtocolGuid
,
919 This
->DriverBindingHandle
,
926 AllChildrenStopped
= TRUE
;
928 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
930 Status
= gBS
->OpenProtocol (
931 ChildHandleBuffer
[Index
],
932 &gEfiSimpleTextOutProtocolGuid
,
933 (VOID
**) &SimpleTextOutput
,
934 This
->DriverBindingHandle
,
935 ChildHandleBuffer
[Index
],
936 EFI_OPEN_PROTOCOL_GET_PROTOCOL
938 if (!EFI_ERROR (Status
)) {
940 TerminalDevice
= TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput
);
944 &gEfiSerialIoProtocolGuid
,
945 This
->DriverBindingHandle
,
946 ChildHandleBuffer
[Index
]
949 Status
= gBS
->UninstallMultipleProtocolInterfaces (
950 ChildHandleBuffer
[Index
],
951 &gEfiSimpleTextInProtocolGuid
,
952 &TerminalDevice
->SimpleInput
,
953 &gEfiSimpleTextInputExProtocolGuid
,
954 &TerminalDevice
->SimpleInputEx
,
955 &gEfiSimpleTextOutProtocolGuid
,
956 &TerminalDevice
->SimpleTextOutput
,
957 &gEfiDevicePathProtocolGuid
,
958 TerminalDevice
->DevicePath
,
961 if (EFI_ERROR (Status
)) {
964 &gEfiSerialIoProtocolGuid
,
966 This
->DriverBindingHandle
,
967 ChildHandleBuffer
[Index
],
968 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
972 FreeUnicodeStringTable (TerminalDevice
->ControllerNameTable
);
973 StopTerminalStateMachine (TerminalDevice
);
974 gBS
->CloseEvent (TerminalDevice
->SimpleInput
.WaitForKey
);
975 gBS
->CloseEvent (TerminalDevice
->SimpleInputEx
.WaitForKeyEx
);
976 gBS
->CloseEvent (TerminalDevice
->KeyNotifyProcessEvent
);
977 TerminalFreeNotifyList (&TerminalDevice
->NotifyList
);
978 FreePool (TerminalDevice
->DevicePath
);
979 FreePool (TerminalDevice
->TerminalConsoleModeData
);
980 FreePool (TerminalDevice
);
984 if (EFI_ERROR (Status
)) {
985 AllChildrenStopped
= FALSE
;
989 if (!AllChildrenStopped
) {
990 return EFI_DEVICE_ERROR
;
997 Compare a device path data structure to that of all the nodes of a
998 second device path instance.
1000 @param Multi A pointer to a multi-instance device path data structure.
1001 @param Single A pointer to a single-instance device path data structure.
1003 @retval TRUE If the Single is contained within Multi.
1004 @retval FALSE The Single is not match within Multi.
1009 IN EFI_DEVICE_PATH_PROTOCOL
*Multi
,
1010 IN EFI_DEVICE_PATH_PROTOCOL
*Single
1013 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1014 EFI_DEVICE_PATH_PROTOCOL
*DevicePathInst
;
1018 DevicePathInst
= GetNextDevicePathInstance (&DevicePath
, &Size
);
1020 // Search for the match of 'Single' in 'Multi'
1022 while (DevicePathInst
!= NULL
) {
1024 // If the single device path is found in multiple device paths,
1027 if (CompareMem (Single
, DevicePathInst
, Size
) == 0) {
1028 FreePool (DevicePathInst
);
1032 FreePool (DevicePathInst
);
1033 DevicePathInst
= GetNextDevicePathInstance (&DevicePath
, &Size
);
1040 Update terminal device path in Console Device Environment Variables.
1042 @param VariableName The Console Device Environment Variable.
1043 @param ParentDevicePath The terminal device path to be updated.
1047 TerminalUpdateConsoleDevVariable (
1048 IN CHAR16
*VariableName
,
1049 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
1055 TERMINAL_TYPE TerminalType
;
1056 EFI_DEVICE_PATH_PROTOCOL
*Variable
;
1057 EFI_DEVICE_PATH_PROTOCOL
*NewVariable
;
1058 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1059 EDKII_SET_VARIABLE_STATUS
*SetVariableStatus
;
1062 // Get global variable and its size according to the name given.
1064 Status
= GetEfiGlobalVariable2 (VariableName
, (VOID
**)&Variable
, NULL
);
1065 if (Status
== EFI_NOT_FOUND
) {
1066 Status
= EFI_SUCCESS
;
1069 if (EFI_ERROR (Status
)) {
1074 // Append terminal device path onto the variable.
1076 for (TerminalType
= 0; TerminalType
< ARRAY_SIZE (mTerminalType
); TerminalType
++) {
1077 SetTerminalDevicePath (TerminalType
, ParentDevicePath
, &TempDevicePath
);
1079 if (TempDevicePath
!= NULL
) {
1080 if (!MatchDevicePaths (Variable
, TempDevicePath
)) {
1081 NewVariable
= AppendDevicePathInstance (Variable
, TempDevicePath
);
1082 if (NewVariable
!= NULL
) {
1083 if (Variable
!= NULL
) {
1084 FreePool (Variable
);
1086 Variable
= NewVariable
;
1090 FreePool (TempDevicePath
);
1095 VariableSize
= GetDevicePathSize (Variable
);
1097 Status
= gRT
->SetVariable (
1099 &gEfiGlobalVariableGuid
,
1100 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1105 if (EFI_ERROR (Status
)) {
1106 NameSize
= StrSize (VariableName
);
1107 SetVariableStatus
= AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS
) + NameSize
+ VariableSize
);
1108 if (SetVariableStatus
!= NULL
) {
1109 CopyGuid (&SetVariableStatus
->Guid
, &gEfiGlobalVariableGuid
);
1110 SetVariableStatus
->NameSize
= NameSize
;
1111 SetVariableStatus
->DataSize
= VariableSize
;
1112 SetVariableStatus
->SetStatus
= Status
;
1113 SetVariableStatus
->Attributes
= EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
;
1114 CopyMem (SetVariableStatus
+ 1, VariableName
, NameSize
);
1115 CopyMem (((UINT8
*) (SetVariableStatus
+ 1)) + NameSize
, Variable
, VariableSize
);
1117 REPORT_STATUS_CODE_EX (
1119 PcdGet32 (PcdErrorCodeSetVariable
),
1122 &gEdkiiStatusCodeDataTypeVariableGuid
,
1124 sizeof (EDKII_SET_VARIABLE_STATUS
) + NameSize
+ VariableSize
1127 FreePool (SetVariableStatus
);
1131 FreePool (Variable
);
1138 Remove terminal device path from Console Device Environment Variables.
1140 @param VariableName Console Device Environment Variables.
1141 @param ParentDevicePath The terminal device path to be updated.
1145 TerminalRemoveConsoleDevVariable (
1146 IN CHAR16
*VariableName
,
1147 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
1155 TERMINAL_TYPE TerminalType
;
1156 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
1157 EFI_DEVICE_PATH_PROTOCOL
*Variable
;
1158 EFI_DEVICE_PATH_PROTOCOL
*OriginalVariable
;
1159 EFI_DEVICE_PATH_PROTOCOL
*NewVariable
;
1160 EFI_DEVICE_PATH_PROTOCOL
*SavedNewVariable
;
1161 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1166 // Get global variable and its size according to the name given.
1168 GetEfiGlobalVariable2 (VariableName
, (VOID
**)&Variable
, NULL
);
1169 if (Variable
== NULL
) {
1174 OriginalVariable
= Variable
;
1178 // Get first device path instance from Variable
1180 Instance
= GetNextDevicePathInstance (&Variable
, &InstanceSize
);
1181 if (Instance
== NULL
) {
1182 FreePool (OriginalVariable
);
1186 // Loop through all the device path instances of Variable
1190 // Loop through all the terminal types that this driver supports
1193 for (TerminalType
= 0; TerminalType
< ARRAY_SIZE (mTerminalType
); TerminalType
++) {
1195 SetTerminalDevicePath (TerminalType
, ParentDevicePath
, &TempDevicePath
);
1198 // Compare the generated device path to the current device path instance
1200 if (TempDevicePath
!= NULL
) {
1201 if (CompareMem (Instance
, TempDevicePath
, InstanceSize
) == 0) {
1206 FreePool (TempDevicePath
);
1210 // If a match was not found, then keep the current device path instance
1213 SavedNewVariable
= NewVariable
;
1214 NewVariable
= AppendDevicePathInstance (NewVariable
, Instance
);
1215 if (SavedNewVariable
!= NULL
) {
1216 FreePool (SavedNewVariable
);
1220 // Get next device path instance from Variable
1222 FreePool (Instance
);
1223 Instance
= GetNextDevicePathInstance (&Variable
, &InstanceSize
);
1224 } while (Instance
!= NULL
);
1226 FreePool (OriginalVariable
);
1229 VariableSize
= GetDevicePathSize (NewVariable
);
1231 Status
= gRT
->SetVariable (
1233 &gEfiGlobalVariableGuid
,
1234 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1239 // Shrinking variable with existing variable driver implementation shouldn't fail.
1241 ASSERT_EFI_ERROR (Status
);
1244 if (NewVariable
!= NULL
) {
1245 FreePool (NewVariable
);
1252 Build terminal device path according to terminal type.
1254 @param TerminalType The terminal type is PC ANSI, VT100, VT100+ or VT-UTF8.
1255 @param ParentDevicePath Parent device path.
1256 @param TerminalDevicePath Returned terminal device path, if building successfully.
1258 @retval EFI_UNSUPPORTED Terminal does not belong to the supported type.
1259 @retval EFI_OUT_OF_RESOURCES Generate terminal device path failed.
1260 @retval EFI_SUCCESS Build terminal device path successfully.
1264 SetTerminalDevicePath (
1265 IN TERMINAL_TYPE TerminalType
,
1266 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
1267 OUT EFI_DEVICE_PATH_PROTOCOL
**TerminalDevicePath
1270 VENDOR_DEVICE_PATH Node
;
1272 ASSERT (TerminalType
< ARRAY_SIZE (mTerminalType
));
1273 Node
.Header
.Type
= MESSAGING_DEVICE_PATH
;
1274 Node
.Header
.SubType
= MSG_VENDOR_DP
;
1275 SetDevicePathNodeLength (&Node
.Header
, sizeof (VENDOR_DEVICE_PATH
));
1276 CopyGuid (&Node
.Guid
, mTerminalType
[TerminalType
]);
1279 // Append the terminal node onto parent device path
1280 // to generate a complete terminal device path.
1282 *TerminalDevicePath
= AppendDevicePathNode (
1284 (EFI_DEVICE_PATH_PROTOCOL
*) &Node
1286 if (*TerminalDevicePath
== NULL
) {
1287 return EFI_OUT_OF_RESOURCES
;
1294 The user Entry Point for module Terminal. The user code starts with this function.
1296 @param ImageHandle The firmware allocated handle for the EFI image.
1297 @param SystemTable A pointer to the EFI System Table.
1299 @retval EFI_SUCCESS The entry point is executed successfully.
1300 @retval other Some error occurs when executing this entry point.
1306 IN EFI_HANDLE ImageHandle
,
1307 IN EFI_SYSTEM_TABLE
*SystemTable
1313 // Install driver model protocol(s).
1315 Status
= EfiLibInstallDriverBindingComponentName2 (
1318 &gTerminalDriverBinding
,
1320 &gTerminalComponentName
,
1321 &gTerminalComponentName2
1323 ASSERT_EFI_ERROR (Status
);
1329 Check if the device supports hot-plug through its device path.
1331 This function could be updated to check more types of Hot Plug devices.
1332 Currently, it checks USB and PCCard device.
1334 @param DevicePath Pointer to device's device path.
1336 @retval TRUE The devcie is a hot-plug device
1337 @retval FALSE The devcie is not a hot-plug device.
1342 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1345 EFI_DEVICE_PATH_PROTOCOL
*CheckDevicePath
;
1347 CheckDevicePath
= DevicePath
;
1348 while (!IsDevicePathEnd (CheckDevicePath
)) {
1350 // Check device whether is hot plug device or not throught Device Path
1352 if ((DevicePathType (CheckDevicePath
) == MESSAGING_DEVICE_PATH
) &&
1353 (DevicePathSubType (CheckDevicePath
) == MSG_USB_DP
||
1354 DevicePathSubType (CheckDevicePath
) == MSG_USB_CLASS_DP
||
1355 DevicePathSubType (CheckDevicePath
) == MSG_USB_WWID_DP
)) {
1357 // If Device is USB device
1361 if ((DevicePathType (CheckDevicePath
) == HARDWARE_DEVICE_PATH
) &&
1362 (DevicePathSubType (CheckDevicePath
) == HW_PCCARD_DP
)) {
1364 // If Device is PCCard
1369 CheckDevicePath
= NextDevicePathNode (CheckDevicePath
);