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 - 2010, Intel Corporation. <BR>
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
22 EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding
= {
23 TerminalDriverBindingSupported
,
24 TerminalDriverBindingStart
,
25 TerminalDriverBindingStop
,
32 EFI_GUID
*gTerminalType
[] = {
40 TERMINAL_DEV mTerminalDevTemplate
= {
41 TERMINAL_DEV_SIGNATURE
,
48 TerminalConInReadKeyStroke
,
53 TerminalConOutOutputString
,
54 TerminalConOutTestString
,
55 TerminalConOutQueryMode
,
56 TerminalConOutSetMode
,
57 TerminalConOutSetAttribute
,
58 TerminalConOutClearScreen
,
59 TerminalConOutSetCursorPosition
,
60 TerminalConOutEnableCursor
,
63 { // SimpleTextOutputMode
66 EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
), // Attribute
77 NULL
, // ControllerNameTable
78 NULL
, // TwoSecondTimeOut
82 { // SimpleTextInputEx
84 TerminalConInReadKeyStrokeEx
,
86 TerminalConInSetState
,
87 TerminalConInRegisterKeyNotify
,
88 TerminalConInUnregisterKeyNotify
,
97 Test to see if this driver supports Controller.
99 @param This Protocol instance pointer.
100 @param Controller Handle of device to test
101 @param RemainingDevicePath Optional parameter use to pick a specific child
104 @retval EFI_SUCCESS This driver supports this device.
105 @retval EFI_ALREADY_STARTED This driver is already running on this device.
106 @retval other This driver does not support this device.
111 TerminalDriverBindingSupported (
112 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
113 IN EFI_HANDLE Controller
,
114 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
118 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
119 EFI_SERIAL_IO_PROTOCOL
*SerialIo
;
120 VENDOR_DEVICE_PATH
*Node
;
123 // If remaining device path is not NULL, then make sure it is a
124 // device path that describes a terminal communications protocol.
126 if (RemainingDevicePath
!= NULL
) {
128 // Check if RemainingDevicePath is the End of Device Path Node,
129 // if yes, go on checking other conditions
131 if (!IsDevicePathEnd (RemainingDevicePath
)) {
133 // If RemainingDevicePath isn't the End of Device Path Node,
134 // check its validation
136 Node
= (VENDOR_DEVICE_PATH
*) RemainingDevicePath
;
138 if (Node
->Header
.Type
!= MESSAGING_DEVICE_PATH
||
139 Node
->Header
.SubType
!= MSG_VENDOR_DP
||
140 DevicePathNodeLength(&Node
->Header
) != sizeof(VENDOR_DEVICE_PATH
)) {
142 return EFI_UNSUPPORTED
;
146 // only supports PC ANSI, VT100, VT100+ and VT-UTF8 terminal types
148 if (!CompareGuid (&Node
->Guid
, &gEfiPcAnsiGuid
) &&
149 !CompareGuid (&Node
->Guid
, &gEfiVT100Guid
) &&
150 !CompareGuid (&Node
->Guid
, &gEfiVT100PlusGuid
) &&
151 !CompareGuid (&Node
->Guid
, &gEfiVTUTF8Guid
)) {
153 return EFI_UNSUPPORTED
;
158 // Open the IO Abstraction(s) needed to perform the supported test
159 // The Controller must support the Serial I/O Protocol.
160 // This driver is a bus driver with at most 1 child device, so it is
161 // ok for it to be already started.
163 Status
= gBS
->OpenProtocol (
165 &gEfiSerialIoProtocolGuid
,
167 This
->DriverBindingHandle
,
169 EFI_OPEN_PROTOCOL_BY_DRIVER
171 if (Status
== EFI_ALREADY_STARTED
) {
175 if (EFI_ERROR (Status
)) {
180 // Close the I/O Abstraction(s) used to perform the supported test
184 &gEfiSerialIoProtocolGuid
,
185 This
->DriverBindingHandle
,
190 // Open the EFI Device Path protocol needed to perform the supported test
192 Status
= gBS
->OpenProtocol (
194 &gEfiDevicePathProtocolGuid
,
195 (VOID
**) &ParentDevicePath
,
196 This
->DriverBindingHandle
,
198 EFI_OPEN_PROTOCOL_BY_DRIVER
200 if (Status
== EFI_ALREADY_STARTED
) {
204 if (EFI_ERROR (Status
)) {
209 // Close protocol, don't use device path protocol in the Support() function
213 &gEfiDevicePathProtocolGuid
,
214 This
->DriverBindingHandle
,
222 Build the terminal device path for the child device according to the
225 @param ParentDevicePath Parent device path.
226 @param RemainingDevicePath A specific child device.
228 @return The child device path built.
231 EFI_DEVICE_PATH_PROTOCOL
*
233 BuildTerminalDevpath (
234 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
235 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
238 EFI_DEVICE_PATH_PROTOCOL
*TerminalDevicePath
;
240 VENDOR_DEVICE_PATH
*Node
;
243 TerminalDevicePath
= NULL
;
244 TerminalType
= PCANSITYPE
;
247 // Use the RemainingDevicePath to determine the terminal type
249 Node
= (VENDOR_DEVICE_PATH
*) RemainingDevicePath
;
251 TerminalType
= PCANSITYPE
;
253 } else if (CompareGuid (&Node
->Guid
, &gEfiPcAnsiGuid
)) {
255 TerminalType
= PCANSITYPE
;
257 } else if (CompareGuid (&Node
->Guid
, &gEfiVT100Guid
)) {
259 TerminalType
= VT100TYPE
;
261 } else if (CompareGuid (&Node
->Guid
, &gEfiVT100PlusGuid
)) {
263 TerminalType
= VT100PLUSTYPE
;
265 } else if (CompareGuid (&Node
->Guid
, &gEfiVTUTF8Guid
)) {
267 TerminalType
= VTUTF8TYPE
;
274 // Build the device path for the child device
276 Status
= SetTerminalDevicePath (
281 if (EFI_ERROR (Status
)) {
284 return TerminalDevicePath
;
288 Compare a device path data structure to that of all the nodes of a
289 second device path instance.
291 @param Multi A pointer to a multi-instance device path data structure.
292 @param Single A pointer to a single-instance device path data structure.
294 @retval TRUE If the Single is contained within Multi.
295 @retval FALSE The Single is not match within Multi.
300 IN EFI_DEVICE_PATH_PROTOCOL
*Multi
,
301 IN EFI_DEVICE_PATH_PROTOCOL
*Single
304 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
305 EFI_DEVICE_PATH_PROTOCOL
*DevicePathInst
;
309 DevicePathInst
= GetNextDevicePathInstance (&DevicePath
, &Size
);
311 // Search for the match of 'Single' in 'Multi'
313 while (DevicePathInst
!= NULL
) {
315 // If the single device path is found in multiple device paths,
318 if (CompareMem (Single
, DevicePathInst
, Size
) == 0) {
319 FreePool (DevicePathInst
);
323 FreePool (DevicePathInst
);
324 DevicePathInst
= GetNextDevicePathInstance (&DevicePath
, &Size
);
331 Check whether the terminal device path is in the global variable.
333 @param VariableName Pointer to one global variable.
334 @param TerminalDevicePath Pointer to the terminal device's device path.
336 @retval TRUE The devcie is in the global variable.
337 @retval FALSE The devcie is not in the global variable.
341 IsTerminalInConsoleVariable (
342 IN CHAR16
*VariableName
,
343 IN EFI_DEVICE_PATH_PROTOCOL
*TerminalDevicePath
346 EFI_DEVICE_PATH_PROTOCOL
*Variable
;
350 // Get global variable and its size according to the name given.
352 Variable
= GetEfiGlobalVariable (VariableName
);
353 if (Variable
== NULL
) {
358 // Check whether the terminal device path is one of the variable instances.
360 ReturnFlag
= MatchDevicePaths (Variable
, TerminalDevicePath
);
368 Free notify functions list.
370 @param ListHead The list head
372 @retval EFI_SUCCESS Free the notify list successfully.
373 @retval EFI_INVALID_PARAMETER ListHead is NULL.
377 TerminalFreeNotifyList (
378 IN OUT LIST_ENTRY
*ListHead
381 TERMINAL_CONSOLE_IN_EX_NOTIFY
*NotifyNode
;
383 if (ListHead
== NULL
) {
384 return EFI_INVALID_PARAMETER
;
386 while (!IsListEmpty (ListHead
)) {
388 ListHead
->ForwardLink
,
389 TERMINAL_CONSOLE_IN_EX_NOTIFY
,
391 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
393 RemoveEntryList (ListHead
->ForwardLink
);
394 FreePool (NotifyNode
);
402 Start this driver on Controller by opening a Serial IO protocol,
403 reading Device Path, and creating a child handle with a Simple Text In,
404 Simple Text In Ex and Simple Text Out protocol, and device path protocol.
405 And store Console Device Environment Variables.
407 @param This Protocol instance pointer.
408 @param Controller Handle of device to bind driver to
409 @param RemainingDevicePath Optional parameter use to pick a specific child
412 @retval EFI_SUCCESS This driver is added to Controller.
413 @retval EFI_ALREADY_STARTED This driver is already running on Controller.
414 @retval other This driver does not support this device.
419 TerminalDriverBindingStart (
420 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
421 IN EFI_HANDLE Controller
,
422 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
426 EFI_SERIAL_IO_PROTOCOL
*SerialIo
;
427 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
428 VENDOR_DEVICE_PATH
*Node
;
429 VENDOR_DEVICE_PATH
*DefaultNode
;
430 EFI_SERIAL_IO_MODE
*Mode
;
431 UINTN SerialInTimeOut
;
432 TERMINAL_DEV
*TerminalDevice
;
434 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
*OpenInfoBuffer
;
437 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
438 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*SimpleTextOutput
;
439 EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*SimpleTextInput
;
440 BOOLEAN ConInSelected
;
441 BOOLEAN ConOutSelected
;
442 BOOLEAN NullRemaining
;
443 BOOLEAN SimTxtInInstalled
;
444 BOOLEAN SimTxtOutInstalled
;
447 TerminalDevice
= NULL
;
449 ConInSelected
= FALSE
;
450 ConOutSelected
= FALSE
;
451 NullRemaining
= TRUE
;
452 SimTxtInInstalled
= FALSE
;
453 SimTxtOutInstalled
= FALSE
;
456 // Get the Device Path Protocol to build the device path of the child device
458 Status
= gBS
->OpenProtocol (
460 &gEfiDevicePathProtocolGuid
,
461 (VOID
**) &ParentDevicePath
,
462 This
->DriverBindingHandle
,
464 EFI_OPEN_PROTOCOL_BY_DRIVER
466 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
471 // Open the Serial I/O Protocol BY_DRIVER. It might already be started.
473 Status
= gBS
->OpenProtocol (
475 &gEfiSerialIoProtocolGuid
,
477 This
->DriverBindingHandle
,
479 EFI_OPEN_PROTOCOL_BY_DRIVER
481 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
485 if (Status
!= EFI_ALREADY_STARTED
) {
487 // the serial I/O protocol never be opened before, it is the first
488 // time to start the serial Io controller
494 // Serial I/O is not already open by this driver, then tag the handle
495 // with the Terminal Driver GUID and update the ConInDev, ConOutDev, and
496 // StdErrDev variables with the list of possible terminal types on this
499 Status
= gBS
->OpenProtocol (
503 This
->DriverBindingHandle
,
505 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
507 if (EFI_ERROR (Status
)) {
508 Status
= gBS
->InstallMultipleProtocolInterfaces (
511 DuplicateDevicePath (ParentDevicePath
),
514 if (EFI_ERROR (Status
)) {
518 if (!IsHotPlugDevice (ParentDevicePath
)) {
520 // if the serial device is a hot plug device, do not update the
521 // ConInDev, ConOutDev, and StdErrDev variables.
523 TerminalUpdateConsoleDevVariable (L
"ConInDev", ParentDevicePath
);
524 TerminalUpdateConsoleDevVariable (L
"ConOutDev", ParentDevicePath
);
525 TerminalUpdateConsoleDevVariable (L
"ErrOutDev", ParentDevicePath
);
530 // Check the requirement for the SimpleTxtIn and SimpleTxtOut protocols
532 // Simple In/Out Protocol will not be installed onto the handle if the
533 // device path to the handle is not present in the ConIn/ConOut
534 // environment variable. But If RemainingDevicePath is NULL, then always
535 // produce both Simple In and Simple Text Output Protocols. This is required
536 // for the connect all sequences to make sure all possible consoles are
537 // produced no matter what the current values of ConIn, ConOut, or StdErr are.
539 if (RemainingDevicePath
== NULL
) {
540 NullRemaining
= TRUE
;
543 DevicePath
= BuildTerminalDevpath (ParentDevicePath
, RemainingDevicePath
);
544 if (DevicePath
!= NULL
) {
545 ConInSelected
= IsTerminalInConsoleVariable (L
"ConIn", DevicePath
);
546 ConOutSelected
= IsTerminalInConsoleVariable (L
"ConOut", DevicePath
);
547 FreePool (DevicePath
);
552 // Not create the child terminal handle if both Simple In/In Ex and
553 // Simple text Out protocols are not required to be published
555 if ((!ConInSelected
)&&(!ConOutSelected
)&&(!NullRemaining
)) {
560 // create the child terminal handle during first entry
564 // First enther the start funciton
568 // Make sure a child handle does not already exist. This driver can only
569 // produce one child per serial port.
571 Status
= gBS
->OpenProtocolInformation (
573 &gEfiSerialIoProtocolGuid
,
577 if (!EFI_ERROR (Status
)) {
578 Status
= EFI_SUCCESS
;
579 for (Index
= 0; Index
< EntryCount
; Index
++) {
580 if ((OpenInfoBuffer
[Index
].Attributes
& EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
) != 0) {
581 Status
= EFI_ALREADY_STARTED
;
585 FreePool (OpenInfoBuffer
);
586 if (EFI_ERROR (Status
)) {
592 // If RemainingDevicePath is NULL, then create default device path node
594 if (RemainingDevicePath
== NULL
) {
595 DefaultNode
= AllocateZeroPool (sizeof (VENDOR_DEVICE_PATH
));
596 if (DefaultNode
== NULL
) {
597 Status
= EFI_OUT_OF_RESOURCES
;
601 TerminalType
= PcdGet8 (PcdDefaultTerminalType
);
603 // Must be between PCANSITYPE (0) and VTUTF8TYPE (3)
605 ASSERT (TerminalType
<= VTUTF8TYPE
);
607 CopyMem (&DefaultNode
->Guid
, gTerminalType
[TerminalType
], sizeof (EFI_GUID
));
608 RemainingDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) DefaultNode
;
609 } else if (!IsDevicePathEnd (RemainingDevicePath
)) {
611 // If RemainingDevicePath isn't the End of Device Path Node,
612 // Use the RemainingDevicePath to determine the terminal type
614 Node
= (VENDOR_DEVICE_PATH
*)RemainingDevicePath
;
615 if (CompareGuid (&Node
->Guid
, &gEfiPcAnsiGuid
)) {
616 TerminalType
= PCANSITYPE
;
617 } else if (CompareGuid (&Node
->Guid
, &gEfiVT100Guid
)) {
618 TerminalType
= VT100TYPE
;
619 } else if (CompareGuid (&Node
->Guid
, &gEfiVT100PlusGuid
)) {
620 TerminalType
= VT100PLUSTYPE
;
621 } else if (CompareGuid (&Node
->Guid
, &gEfiVTUTF8Guid
)) {
622 TerminalType
= VTUTF8TYPE
;
628 // If RemainingDevicePath is the End of Device Path Node,
629 // skip enumerate any device and return EFI_SUCESSS
635 // Initialize the Terminal Dev
637 TerminalDevice
= AllocateCopyPool (sizeof (TERMINAL_DEV
), &mTerminalDevTemplate
);
638 if (TerminalDevice
== NULL
) {
639 Status
= EFI_OUT_OF_RESOURCES
;
643 TerminalDevice
->TerminalType
= TerminalType
;
644 TerminalDevice
->SerialIo
= SerialIo
;
646 InitializeListHead (&TerminalDevice
->NotifyList
);
647 Status
= gBS
->CreateEvent (
650 TerminalConInWaitForKeyEx
,
651 &TerminalDevice
->SimpleInputEx
,
652 &TerminalDevice
->SimpleInputEx
.WaitForKeyEx
654 if (EFI_ERROR (Status
)) {
658 Status
= gBS
->CreateEvent (
661 TerminalConInWaitForKey
,
662 &TerminalDevice
->SimpleInput
,
663 &TerminalDevice
->SimpleInput
.WaitForKey
665 if (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
) {
686 // Set the timeout value of serial buffer for
687 // keystroke response performance issue
689 Mode
= TerminalDevice
->SerialIo
->Mode
;
692 if (Mode
->BaudRate
!= 0) {
693 SerialInTimeOut
= (1 + Mode
->DataBits
+ Mode
->StopBits
) * 2 * 1000000 / (UINTN
) Mode
->BaudRate
;
696 Status
= TerminalDevice
->SerialIo
->SetAttributes (
697 TerminalDevice
->SerialIo
,
699 Mode
->ReceiveFifoDepth
,
700 (UINT32
) SerialInTimeOut
,
701 (EFI_PARITY_TYPE
) (Mode
->Parity
),
702 (UINT8
) Mode
->DataBits
,
703 (EFI_STOP_BITS_TYPE
) (Mode
->StopBits
)
705 if (EFI_ERROR (Status
)) {
707 // if set attributes operation fails, invalidate
708 // the value of SerialInTimeOut,thus make it
709 // inconsistent with the default timeout value
710 // of serial buffer. This will invoke the recalculation
711 // in the readkeystroke routine.
713 TerminalDevice
->SerialInTimeOut
= 0;
715 TerminalDevice
->SerialInTimeOut
= SerialInTimeOut
;
718 // Set Simple Text Output Protocol from template.
720 SimpleTextOutput
= CopyMem (
721 &TerminalDevice
->SimpleTextOutput
,
722 &mTerminalDevTemplate
.SimpleTextOutput
,
723 sizeof (mTerminalDevTemplate
.SimpleTextOutput
)
725 SimpleTextOutput
->Mode
= &TerminalDevice
->SimpleTextOutputMode
;
727 TerminalDevice
->SimpleTextOutputMode
.MaxMode
= 3;
729 // For terminal devices, cursor is always visible
731 TerminalDevice
->SimpleTextOutputMode
.CursorVisible
= TRUE
;
732 Status
= TerminalConOutSetAttribute (
734 EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
)
736 if (EFI_ERROR (Status
)) {
740 Status
= TerminalConOutReset (SimpleTextOutput
, FALSE
);
741 if (EFI_ERROR (Status
)) {
745 Status
= TerminalConOutSetMode (SimpleTextOutput
, 0);
746 if (EFI_ERROR (Status
)) {
750 Status
= TerminalConOutEnableCursor (SimpleTextOutput
, TRUE
);
751 if (EFI_ERROR (Status
)) {
755 Status
= gBS
->CreateEvent (
760 &TerminalDevice
->TwoSecondTimeOut
764 // Build the component name for the child device
766 TerminalDevice
->ControllerNameTable
= NULL
;
767 switch (TerminalDevice
->TerminalType
) {
771 gTerminalComponentName
.SupportedLanguages
,
772 &TerminalDevice
->ControllerNameTable
,
773 (CHAR16
*)L
"PC-ANSI Serial Console",
778 gTerminalComponentName2
.SupportedLanguages
,
779 &TerminalDevice
->ControllerNameTable
,
780 (CHAR16
*)L
"PC-ANSI Serial Console",
789 gTerminalComponentName
.SupportedLanguages
,
790 &TerminalDevice
->ControllerNameTable
,
791 (CHAR16
*)L
"VT-100 Serial Console",
796 gTerminalComponentName2
.SupportedLanguages
,
797 &TerminalDevice
->ControllerNameTable
,
798 (CHAR16
*)L
"VT-100 Serial Console",
807 gTerminalComponentName
.SupportedLanguages
,
808 &TerminalDevice
->ControllerNameTable
,
809 (CHAR16
*)L
"VT-100+ Serial Console",
814 gTerminalComponentName2
.SupportedLanguages
,
815 &TerminalDevice
->ControllerNameTable
,
816 (CHAR16
*)L
"VT-100+ Serial Console",
825 gTerminalComponentName
.SupportedLanguages
,
826 &TerminalDevice
->ControllerNameTable
,
827 (CHAR16
*)L
"VT-UTF8 Serial Console",
832 gTerminalComponentName2
.SupportedLanguages
,
833 &TerminalDevice
->ControllerNameTable
,
834 (CHAR16
*)L
"VT-UTF8 Serial Console",
842 // Build the device path for the child device
844 Status
= SetTerminalDevicePath (
845 TerminalDevice
->TerminalType
,
847 &TerminalDevice
->DevicePath
849 if (EFI_ERROR (Status
)) {
853 Status
= gBS
->InstallProtocolInterface (
854 &TerminalDevice
->Handle
,
855 &gEfiDevicePathProtocolGuid
,
856 EFI_NATIVE_INTERFACE
,
857 TerminalDevice
->DevicePath
859 if (EFI_ERROR (Status
)) {
864 // Register the Parent-Child relationship via
865 // EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
867 Status
= gBS
->OpenProtocol (
869 &gEfiSerialIoProtocolGuid
,
870 (VOID
**) &TerminalDevice
->SerialIo
,
871 This
->DriverBindingHandle
,
872 TerminalDevice
->Handle
,
873 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
875 if (EFI_ERROR (Status
)) {
881 // Find the child handle, and get its TerminalDevice private data
883 Status
= gBS
->OpenProtocolInformation (
885 &gEfiSerialIoProtocolGuid
,
889 if (!EFI_ERROR (Status
)) {
890 Status
= EFI_NOT_FOUND
;
891 ASSERT (OpenInfoBuffer
!= NULL
);
892 for (Index
= 0; Index
< EntryCount
; Index
++) {
893 if ((OpenInfoBuffer
[Index
].Attributes
& EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
) != 0) {
895 // Find the child terminal handle.
896 // Test whether the SimpleTxtIn and SimpleTxtOut have been published
898 Status
= gBS
->OpenProtocol (
899 OpenInfoBuffer
[Index
].ControllerHandle
,
900 &gEfiSimpleTextInProtocolGuid
,
901 (VOID
**) &SimpleTextInput
,
902 This
->DriverBindingHandle
,
903 OpenInfoBuffer
[Index
].ControllerHandle
,
904 EFI_OPEN_PROTOCOL_GET_PROTOCOL
906 if (!EFI_ERROR (Status
)) {
907 SimTxtInInstalled
= TRUE
;
908 TerminalDevice
= TERMINAL_CON_IN_DEV_FROM_THIS (SimpleTextInput
);
911 Status
= gBS
->OpenProtocol (
912 OpenInfoBuffer
[Index
].ControllerHandle
,
913 &gEfiSimpleTextOutProtocolGuid
,
914 (VOID
**) &SimpleTextOutput
,
915 This
->DriverBindingHandle
,
916 OpenInfoBuffer
[Index
].ControllerHandle
,
917 EFI_OPEN_PROTOCOL_GET_PROTOCOL
919 if (!EFI_ERROR (Status
)) {
920 SimTxtOutInstalled
= TRUE
;
921 TerminalDevice
= TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput
);
923 Status
= EFI_SUCCESS
;
928 FreePool (OpenInfoBuffer
);
929 if (EFI_ERROR (Status
)) {
936 ASSERT (TerminalDevice
!= NULL
);
938 // Only do the reset if the device path is in the Conout variable
940 if (ConInSelected
&& !SimTxtInInstalled
) {
941 Status
= TerminalDevice
->SimpleInput
.Reset (
942 &TerminalDevice
->SimpleInput
,
945 if (EFI_ERROR (Status
)) {
947 // Need to report Error Code first
954 // Only output the configure string to remote terminal if the device path
955 // is in the Conout variable
957 if (ConOutSelected
&& !SimTxtOutInstalled
) {
958 Status
= TerminalDevice
->SimpleTextOutput
.SetAttribute (
959 &TerminalDevice
->SimpleTextOutput
,
960 EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
)
962 if (EFI_ERROR (Status
)) {
966 Status
= TerminalDevice
->SimpleTextOutput
.Reset (
967 &TerminalDevice
->SimpleTextOutput
,
970 if (EFI_ERROR (Status
)) {
974 Status
= TerminalDevice
->SimpleTextOutput
.SetMode (
975 &TerminalDevice
->SimpleTextOutput
,
978 if (EFI_ERROR (Status
)) {
982 Status
= TerminalDevice
->SimpleTextOutput
.EnableCursor (
983 &TerminalDevice
->SimpleTextOutput
,
986 if (EFI_ERROR (Status
)) {
992 // Simple In/Out Protocol will not be installed onto the handle if the
993 // device path to the handle is not present in the ConIn/ConOut
994 // environment variable. But If RemainingDevicePath is NULL, then always
995 // produce both Simple In and Simple Text Output Protocols. This is required
996 // for the connect all sequences to make sure all possible consoles are
997 // produced no matter what the current values of ConIn, ConOut, or StdErr are.
999 if (!SimTxtInInstalled
&& (ConInSelected
|| NullRemaining
)) {
1000 Status
= gBS
->InstallMultipleProtocolInterfaces (
1001 &TerminalDevice
->Handle
,
1002 &gEfiSimpleTextInProtocolGuid
,
1003 &TerminalDevice
->SimpleInput
,
1004 &gEfiSimpleTextInputExProtocolGuid
,
1005 &TerminalDevice
->SimpleInputEx
,
1008 if (EFI_ERROR (Status
)) {
1013 if (!SimTxtOutInstalled
&& (ConOutSelected
|| NullRemaining
)) {
1014 Status
= gBS
->InstallProtocolInterface (
1015 &TerminalDevice
->Handle
,
1016 &gEfiSimpleTextOutProtocolGuid
,
1017 EFI_NATIVE_INTERFACE
,
1018 &TerminalDevice
->SimpleTextOutput
1020 if (EFI_ERROR (Status
)) {
1024 if (DefaultNode
!= NULL
) {
1025 FreePool (DefaultNode
);
1032 // Report error code before exiting
1034 DevicePath
= ParentDevicePath
;
1035 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1036 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1037 (EFI_PERIPHERAL_REMOTE_CONSOLE
| EFI_P_EC_CONTROLLER_ERROR
),
1043 // Use the Stop() function to free all resources allocated in Start()
1045 if (TerminalDevice
!= NULL
) {
1047 if (TerminalDevice
->Handle
!= NULL
) {
1048 This
->Stop (This
, Controller
, 1, &TerminalDevice
->Handle
);
1051 if (TerminalDevice
->TwoSecondTimeOut
!= NULL
) {
1052 gBS
->CloseEvent (TerminalDevice
->TwoSecondTimeOut
);
1055 if (TerminalDevice
->SimpleInput
.WaitForKey
!= NULL
) {
1056 gBS
->CloseEvent (TerminalDevice
->SimpleInput
.WaitForKey
);
1059 if (TerminalDevice
->SimpleInputEx
.WaitForKeyEx
!= NULL
) {
1060 gBS
->CloseEvent (TerminalDevice
->SimpleInputEx
.WaitForKeyEx
);
1063 TerminalFreeNotifyList (&TerminalDevice
->NotifyList
);
1065 if (TerminalDevice
->RawFiFo
!= NULL
) {
1066 FreePool (TerminalDevice
->RawFiFo
);
1068 if (TerminalDevice
->UnicodeFiFo
!= NULL
) {
1069 FreePool (TerminalDevice
->UnicodeFiFo
);
1071 if (TerminalDevice
->EfiKeyFiFo
!= NULL
) {
1072 FreePool (TerminalDevice
->EfiKeyFiFo
);
1075 if (TerminalDevice
->ControllerNameTable
!= NULL
) {
1076 FreeUnicodeStringTable (TerminalDevice
->ControllerNameTable
);
1079 if (TerminalDevice
->DevicePath
!= NULL
) {
1080 FreePool (TerminalDevice
->DevicePath
);
1083 FreePool (TerminalDevice
);
1087 if (DefaultNode
!= NULL
) {
1088 FreePool (DefaultNode
);
1091 This
->Stop (This
, Controller
, 0, NULL
);
1097 Stop this driver on Controller by closing Simple Text In, Simple Text
1098 In Ex, Simple Text Out protocol, and removing parent device path from
1099 Console Device Environment Variables.
1101 @param This Protocol instance pointer.
1102 @param Controller Handle of device to stop driver on
1103 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
1104 children is zero stop the entire bus driver.
1105 @param ChildHandleBuffer List of Child Handles to Stop.
1107 @retval EFI_SUCCESS This driver is removed Controller.
1108 @retval other This driver could not be removed from this device.
1113 TerminalDriverBindingStop (
1114 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1115 IN EFI_HANDLE Controller
,
1116 IN UINTN NumberOfChildren
,
1117 IN EFI_HANDLE
*ChildHandleBuffer
1122 BOOLEAN AllChildrenStopped
;
1123 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*SimpleTextOutput
;
1124 TERMINAL_DEV
*TerminalDevice
;
1125 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
1126 EFI_SERIAL_IO_PROTOCOL
*SerialIo
;
1127 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1129 Status
= gBS
->HandleProtocol (
1131 &gEfiDevicePathProtocolGuid
,
1132 (VOID
**) &DevicePath
1134 if (EFI_ERROR (Status
)) {
1139 // Complete all outstanding transactions to Controller.
1140 // Don't allow any new transaction to Controller to be started.
1142 if (NumberOfChildren
== 0) {
1144 // Close the bus driver
1146 Status
= gBS
->OpenProtocol (
1149 (VOID
**) &ParentDevicePath
,
1150 This
->DriverBindingHandle
,
1152 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1154 if (!EFI_ERROR (Status
)) {
1156 // Remove Parent Device Path from
1157 // the Console Device Environment Variables
1159 TerminalRemoveConsoleDevVariable (L
"ConInDev", ParentDevicePath
);
1160 TerminalRemoveConsoleDevVariable (L
"ConOutDev", ParentDevicePath
);
1161 TerminalRemoveConsoleDevVariable (L
"ErrOutDev", ParentDevicePath
);
1164 // Uninstall the Terminal Driver's GUID Tag from the Serial controller
1166 Status
= gBS
->UninstallMultipleProtocolInterfaces (
1174 // Free the ParentDevicePath that was duplicated in Start()
1176 if (!EFI_ERROR (Status
)) {
1177 FreePool (ParentDevicePath
);
1181 gBS
->CloseProtocol (
1183 &gEfiSerialIoProtocolGuid
,
1184 This
->DriverBindingHandle
,
1188 gBS
->CloseProtocol (
1190 &gEfiDevicePathProtocolGuid
,
1191 This
->DriverBindingHandle
,
1198 AllChildrenStopped
= TRUE
;
1200 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
1202 Status
= gBS
->OpenProtocol (
1203 ChildHandleBuffer
[Index
],
1204 &gEfiSimpleTextOutProtocolGuid
,
1205 (VOID
**) &SimpleTextOutput
,
1206 This
->DriverBindingHandle
,
1207 ChildHandleBuffer
[Index
],
1208 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1210 if (!EFI_ERROR (Status
)) {
1212 TerminalDevice
= TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput
);
1214 gBS
->CloseProtocol (
1216 &gEfiSerialIoProtocolGuid
,
1217 This
->DriverBindingHandle
,
1218 ChildHandleBuffer
[Index
]
1221 Status
= gBS
->UninstallMultipleProtocolInterfaces (
1222 ChildHandleBuffer
[Index
],
1223 &gEfiSimpleTextInProtocolGuid
,
1224 &TerminalDevice
->SimpleInput
,
1225 &gEfiSimpleTextInputExProtocolGuid
,
1226 &TerminalDevice
->SimpleInputEx
,
1227 &gEfiSimpleTextOutProtocolGuid
,
1228 &TerminalDevice
->SimpleTextOutput
,
1229 &gEfiDevicePathProtocolGuid
,
1230 TerminalDevice
->DevicePath
,
1233 if (EFI_ERROR (Status
)) {
1236 &gEfiSerialIoProtocolGuid
,
1237 (VOID
**) &SerialIo
,
1238 This
->DriverBindingHandle
,
1239 ChildHandleBuffer
[Index
],
1240 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1244 if (TerminalDevice
->ControllerNameTable
!= NULL
) {
1245 FreeUnicodeStringTable (TerminalDevice
->ControllerNameTable
);
1248 gBS
->CloseEvent (TerminalDevice
->TwoSecondTimeOut
);
1249 gBS
->CloseEvent (TerminalDevice
->SimpleInput
.WaitForKey
);
1250 gBS
->CloseEvent (TerminalDevice
->SimpleInputEx
.WaitForKeyEx
);
1251 TerminalFreeNotifyList (&TerminalDevice
->NotifyList
);
1252 FreePool (TerminalDevice
->DevicePath
);
1253 FreePool (TerminalDevice
);
1257 if (EFI_ERROR (Status
)) {
1258 AllChildrenStopped
= FALSE
;
1262 if (!AllChildrenStopped
) {
1263 return EFI_DEVICE_ERROR
;
1270 Update terminal device path in Console Device Environment Variables.
1272 @param VariableName The Console Device Environment Variable.
1273 @param ParentDevicePath The terminal device path to be updated.
1277 TerminalUpdateConsoleDevVariable (
1278 IN CHAR16
*VariableName
,
1279 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
1285 EFI_DEVICE_PATH_PROTOCOL
*Variable
;
1286 EFI_DEVICE_PATH_PROTOCOL
*NewVariable
;
1287 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1290 // Get global variable and its size according to the name given.
1292 Variable
= GetEfiGlobalVariable (VariableName
);
1293 if (Variable
== NULL
) {
1298 // Append terminal device path onto the variable.
1300 for (TerminalType
= PCANSITYPE
; TerminalType
<= VTUTF8TYPE
; TerminalType
++) {
1301 SetTerminalDevicePath (TerminalType
, ParentDevicePath
, &TempDevicePath
);
1302 NewVariable
= AppendDevicePathInstance (Variable
, TempDevicePath
);
1303 if (Variable
!= NULL
) {
1304 FreePool (Variable
);
1307 if (TempDevicePath
!= NULL
) {
1308 FreePool (TempDevicePath
);
1311 Variable
= NewVariable
;
1314 VariableSize
= GetDevicePathSize (Variable
);
1316 Status
= gRT
->SetVariable (
1318 &gEfiGlobalVariableGuid
,
1319 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1323 ASSERT_EFI_ERROR (Status
);
1324 FreePool (Variable
);
1331 Remove terminal device path from Console Device Environment Variables.
1333 @param VariableName Console Device Environment Variables.
1334 @param ParentDevicePath The terminal device path to be updated.
1338 TerminalRemoveConsoleDevVariable (
1339 IN CHAR16
*VariableName
,
1340 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
1349 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
1350 EFI_DEVICE_PATH_PROTOCOL
*Variable
;
1351 EFI_DEVICE_PATH_PROTOCOL
*OriginalVariable
;
1352 EFI_DEVICE_PATH_PROTOCOL
*NewVariable
;
1353 EFI_DEVICE_PATH_PROTOCOL
*SavedNewVariable
;
1354 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1359 // Get global variable and its size according to the name given.
1361 Variable
= GetEfiGlobalVariable (VariableName
);
1362 if (Variable
== NULL
) {
1367 OriginalVariable
= Variable
;
1371 // Get first device path instance from Variable
1373 Instance
= GetNextDevicePathInstance (&Variable
, &InstanceSize
);
1374 if (Instance
== NULL
) {
1375 FreePool (OriginalVariable
);
1379 // Loop through all the device path instances of Variable
1383 // Loop through all the terminal types that this driver supports
1386 for (TerminalType
= PCANSITYPE
; TerminalType
<= VTUTF8TYPE
; TerminalType
++) {
1388 SetTerminalDevicePath (TerminalType
, ParentDevicePath
, &TempDevicePath
);
1391 // Compare the generated device path to the current device path instance
1393 if (TempDevicePath
!= NULL
) {
1394 if (CompareMem (Instance
, TempDevicePath
, InstanceSize
) == 0) {
1399 FreePool (TempDevicePath
);
1403 // If a match was not found, then keep the current device path instance
1406 SavedNewVariable
= NewVariable
;
1407 NewVariable
= AppendDevicePathInstance (NewVariable
, Instance
);
1408 if (SavedNewVariable
!= NULL
) {
1409 FreePool (SavedNewVariable
);
1413 // Get next device path instance from Variable
1415 FreePool (Instance
);
1416 Instance
= GetNextDevicePathInstance (&Variable
, &InstanceSize
);
1417 } while (Instance
!= NULL
);
1419 FreePool (OriginalVariable
);
1422 VariableSize
= GetDevicePathSize (NewVariable
);
1424 Status
= gRT
->SetVariable (
1426 &gEfiGlobalVariableGuid
,
1427 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1431 ASSERT_EFI_ERROR (Status
);
1434 if (NewVariable
!= NULL
) {
1435 FreePool (NewVariable
);
1442 Build terminal device path according to terminal type.
1444 @param TerminalType The terminal type is PC ANSI, VT100, VT100+ or VT-UTF8.
1445 @param ParentDevicePath Parent device path.
1446 @param TerminalDevicePath Returned terminal device path, if building successfully.
1448 @retval EFI_UNSUPPORTED Terminal does not belong to the supported type.
1449 @retval EFI_OUT_OF_RESOURCES Generate terminal device path failed.
1450 @retval EFI_SUCCESS Build terminal device path successfully.
1454 SetTerminalDevicePath (
1455 IN UINT8 TerminalType
,
1456 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
1457 OUT EFI_DEVICE_PATH_PROTOCOL
**TerminalDevicePath
1460 VENDOR_DEVICE_PATH Node
;
1462 *TerminalDevicePath
= NULL
;
1463 Node
.Header
.Type
= MESSAGING_DEVICE_PATH
;
1464 Node
.Header
.SubType
= MSG_VENDOR_DP
;
1467 // Generate terminal device path node according to terminal type.
1469 switch (TerminalType
) {
1472 CopyGuid (&Node
.Guid
, &gEfiPcAnsiGuid
);
1476 CopyGuid (&Node
.Guid
, &gEfiVT100Guid
);
1480 CopyGuid (&Node
.Guid
, &gEfiVT100PlusGuid
);
1484 CopyGuid (&Node
.Guid
, &gEfiVTUTF8Guid
);
1488 return EFI_UNSUPPORTED
;
1492 // Get VENDOR_DEVCIE_PATH size and put into Node.Header
1494 SetDevicePathNodeLength (
1496 sizeof (VENDOR_DEVICE_PATH
)
1500 // Append the terminal node onto parent device path
1501 // to generate a complete terminal device path.
1503 *TerminalDevicePath
= AppendDevicePathNode (
1505 (EFI_DEVICE_PATH_PROTOCOL
*) &Node
1507 if (*TerminalDevicePath
== NULL
) {
1508 return EFI_OUT_OF_RESOURCES
;
1515 The user Entry Point for module Terminal. The user code starts with this function.
1517 @param ImageHandle The firmware allocated handle for the EFI image.
1518 @param SystemTable A pointer to the EFI System Table.
1520 @retval EFI_SUCCESS The entry point is executed successfully.
1521 @retval other Some error occurs when executing this entry point.
1527 IN EFI_HANDLE ImageHandle
,
1528 IN EFI_SYSTEM_TABLE
*SystemTable
1534 // Install driver model protocol(s).
1536 Status
= EfiLibInstallDriverBindingComponentName2 (
1539 &gTerminalDriverBinding
,
1541 &gTerminalComponentName
,
1542 &gTerminalComponentName2
1544 ASSERT_EFI_ERROR (Status
);
1550 Check if the device supports hot-plug through its device path.
1552 This function could be updated to check more types of Hot Plug devices.
1553 Currently, it checks USB and PCCard device.
1555 @param DevicePath Pointer to device's device path.
1557 @retval TRUE The devcie is a hot-plug device
1558 @retval FALSE The devcie is not a hot-plug device.
1563 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1566 EFI_DEVICE_PATH_PROTOCOL
*CheckDevicePath
;
1568 CheckDevicePath
= DevicePath
;
1569 while (!IsDevicePathEnd (CheckDevicePath
)) {
1571 // Check device whether is hot plug device or not throught Device Path
1573 if ((DevicePathType (CheckDevicePath
) == MESSAGING_DEVICE_PATH
) &&
1574 (DevicePathSubType (CheckDevicePath
) == MSG_USB_DP
||
1575 DevicePathSubType (CheckDevicePath
) == MSG_USB_CLASS_DP
||
1576 DevicePathSubType (CheckDevicePath
) == MSG_USB_WWID_DP
)) {
1578 // If Device is USB device
1582 if ((DevicePathType (CheckDevicePath
) == HARDWARE_DEVICE_PATH
) &&
1583 (DevicePathSubType (CheckDevicePath
) == HW_PCCARD_DP
)) {
1585 // If Device is PCCard
1590 CheckDevicePath
= NextDevicePathNode (CheckDevicePath
);