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 - 2017, Intel Corporation. All rights reserved.<BR>
6 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
*mTerminalType
[] = {
41 CHAR16
*mSerialConsoleNames
[] = {
42 L
"PC-ANSI Serial Console",
43 L
"VT-100 Serial Console",
44 L
"VT-100+ Serial Console",
45 L
"VT-UTF8 Serial Console",
46 L
"Tty Terminal Serial Console"
49 TERMINAL_DEV mTerminalDevTemplate
= {
50 TERMINAL_DEV_SIGNATURE
,
57 TerminalConInReadKeyStroke
,
62 TerminalConOutOutputString
,
63 TerminalConOutTestString
,
64 TerminalConOutQueryMode
,
65 TerminalConOutSetMode
,
66 TerminalConOutSetAttribute
,
67 TerminalConOutClearScreen
,
68 TerminalConOutSetCursorPosition
,
69 TerminalConOutEnableCursor
,
72 { // SimpleTextOutputMode
75 EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
), // Attribute
80 NULL
, // TerminalConsoleModeData
86 NULL
, // EfiKeyFiFoForNotify
88 NULL
, // ControllerNameTable
90 NULL
, // TwoSecondTimeOut
100 { // SimpleTextInputEx
101 TerminalConInResetEx
,
102 TerminalConInReadKeyStrokeEx
,
104 TerminalConInSetState
,
105 TerminalConInRegisterKeyNotify
,
106 TerminalConInUnregisterKeyNotify
,
112 NULL
// KeyNotifyProcessEvent
115 TERMINAL_CONSOLE_MODE_DATA mTerminalConsoleModeData
[] = {
120 // New modes can be added here.
125 Convert the GUID representation of terminal type to enum type.
127 @param Guid The GUID representation of terminal type.
129 @return The terminal type in enum type.
132 TerminalTypeFromGuid (
138 for (Type
= 0; Type
< ARRAY_SIZE (mTerminalType
); Type
++) {
139 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, and TtyTerm terminal types
198 if (TerminalTypeFromGuid (&Node
->Guid
) == ARRAY_SIZE (mTerminalType
)) {
199 return EFI_UNSUPPORTED
;
204 // Open the IO Abstraction(s) needed to perform the supported test
205 // The Controller must support the Serial I/O Protocol.
206 // This driver is a bus driver with at most 1 child device, so it is
207 // ok for it to be already started.
209 Status
= gBS
->OpenProtocol (
211 &gEfiSerialIoProtocolGuid
,
213 This
->DriverBindingHandle
,
215 EFI_OPEN_PROTOCOL_BY_DRIVER
217 if (Status
== EFI_ALREADY_STARTED
) {
221 if (EFI_ERROR (Status
)) {
226 // Close the I/O Abstraction(s) used to perform the supported test
230 &gEfiSerialIoProtocolGuid
,
231 This
->DriverBindingHandle
,
236 // Open the EFI Device Path protocol needed to perform the supported test
238 Status
= gBS
->OpenProtocol (
240 &gEfiDevicePathProtocolGuid
,
241 (VOID
**) &ParentDevicePath
,
242 This
->DriverBindingHandle
,
244 EFI_OPEN_PROTOCOL_BY_DRIVER
246 if (Status
== EFI_ALREADY_STARTED
) {
250 if (EFI_ERROR (Status
)) {
255 // Close protocol, don't use device path protocol in the Support() function
259 &gEfiDevicePathProtocolGuid
,
260 This
->DriverBindingHandle
,
268 Build the terminal device path for the child device according to the
271 @param ParentDevicePath Parent device path.
272 @param RemainingDevicePath A specific child device.
274 @return The child device path built.
277 EFI_DEVICE_PATH_PROTOCOL
*
279 BuildTerminalDevpath (
280 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
281 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
284 EFI_DEVICE_PATH_PROTOCOL
*TerminalDevicePath
;
285 TERMINAL_TYPE TerminalType
;
286 VENDOR_DEVICE_PATH
*Node
;
289 TerminalDevicePath
= NULL
;
292 // Use the RemainingDevicePath to determine the terminal type
294 Node
= (VENDOR_DEVICE_PATH
*) RemainingDevicePath
;
296 TerminalType
= PcdGet8 (PcdDefaultTerminalType
);
298 } else if (CompareGuid (&Node
->Guid
, &gEfiPcAnsiGuid
)) {
300 TerminalType
= TerminalTypePcAnsi
;
302 } else if (CompareGuid (&Node
->Guid
, &gEfiVT100Guid
)) {
304 TerminalType
= TerminalTypeVt100
;
306 } else if (CompareGuid (&Node
->Guid
, &gEfiVT100PlusGuid
)) {
308 TerminalType
= TerminalTypeVt100Plus
;
310 } else if (CompareGuid (&Node
->Guid
, &gEfiVTUTF8Guid
)) {
312 TerminalType
= TerminalTypeVtUtf8
;
314 } else if (CompareGuid (&Node
->Guid
, &gEfiTtyTermGuid
)) {
316 TerminalType
= TerminalTypeTtyTerm
;
323 // Build the device path for the child device
325 Status
= SetTerminalDevicePath (
330 if (EFI_ERROR (Status
)) {
333 return TerminalDevicePath
;
337 Compare a device path data structure to that of all the nodes of a
338 second device path instance.
340 @param Multi A pointer to a multi-instance device path data structure.
341 @param Single A pointer to a single-instance device path data structure.
343 @retval TRUE If the Single is contained within Multi.
344 @retval FALSE The Single is not match within Multi.
349 IN EFI_DEVICE_PATH_PROTOCOL
*Multi
,
350 IN EFI_DEVICE_PATH_PROTOCOL
*Single
353 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
354 EFI_DEVICE_PATH_PROTOCOL
*DevicePathInst
;
358 DevicePathInst
= GetNextDevicePathInstance (&DevicePath
, &Size
);
360 // Search for the match of 'Single' in 'Multi'
362 while (DevicePathInst
!= NULL
) {
364 // If the single device path is found in multiple device paths,
367 if (CompareMem (Single
, DevicePathInst
, Size
) == 0) {
368 FreePool (DevicePathInst
);
372 FreePool (DevicePathInst
);
373 DevicePathInst
= GetNextDevicePathInstance (&DevicePath
, &Size
);
380 Check whether the terminal device path is in the global variable.
382 @param VariableName Pointer to one global variable.
383 @param TerminalDevicePath Pointer to the terminal device's device path.
385 @retval TRUE The devcie is in the global variable.
386 @retval FALSE The devcie is not in the global variable.
390 IsTerminalInConsoleVariable (
391 IN CHAR16
*VariableName
,
392 IN EFI_DEVICE_PATH_PROTOCOL
*TerminalDevicePath
395 EFI_DEVICE_PATH_PROTOCOL
*Variable
;
399 // Get global variable and its size according to the name given.
401 GetEfiGlobalVariable2 (VariableName
, (VOID
**)&Variable
, NULL
);
402 if (Variable
== NULL
) {
407 // Check whether the terminal device path is one of the variable instances.
409 ReturnFlag
= MatchDevicePaths (Variable
, TerminalDevicePath
);
417 Free notify functions list.
419 @param ListHead The list head
421 @retval EFI_SUCCESS Free the notify list successfully.
422 @retval EFI_INVALID_PARAMETER ListHead is NULL.
426 TerminalFreeNotifyList (
427 IN OUT LIST_ENTRY
*ListHead
430 TERMINAL_CONSOLE_IN_EX_NOTIFY
*NotifyNode
;
432 if (ListHead
== NULL
) {
433 return EFI_INVALID_PARAMETER
;
435 while (!IsListEmpty (ListHead
)) {
437 ListHead
->ForwardLink
,
438 TERMINAL_CONSOLE_IN_EX_NOTIFY
,
440 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
442 RemoveEntryList (ListHead
->ForwardLink
);
443 FreePool (NotifyNode
);
450 Initialize all the text modes which the terminal console supports.
452 It returns information for available text modes that the terminal can support.
454 @param[out] TextModeCount The total number of text modes that terminal console supports.
456 @return The buffer to the text modes column and row information.
457 Caller is responsible to free it when it's non-NULL.
460 TERMINAL_CONSOLE_MODE_DATA
*
461 InitializeTerminalConsoleTextMode (
462 OUT INT32
*TextModeCount
465 TERMINAL_CONSOLE_MODE_DATA
*TextModeData
;
467 ASSERT (TextModeCount
!= NULL
);
470 // Here we make sure that the final mode exposed does not include the duplicated modes,
471 // and does not include the invalid modes which exceed the max column and row.
472 // Reserve 2 modes for 80x25, 80x50 of terminal console.
474 TextModeData
= AllocateCopyPool (sizeof (mTerminalConsoleModeData
), mTerminalConsoleModeData
);
475 if (TextModeData
== NULL
) {
478 *TextModeCount
= ARRAY_SIZE (mTerminalConsoleModeData
);
482 for (Index
= 0; Index
< *TextModeCount
; Index
++) {
483 DEBUG ((DEBUG_INFO
, "Terminal - Mode %d, Column = %d, Row = %d\n",
484 Index
, TextModeData
[Index
].Columns
, TextModeData
[Index
].Rows
));
491 Initialize the controller name table.
493 @param TerminalType The terminal type.
494 @param ControllerNameTable The controller name table.
496 @retval EFI_SUCCESS The controller name table is initialized successfully.
497 @retval others Return status of AddUnicodeString2 ().
500 InitializeControllerNameTable (
501 TERMINAL_TYPE TerminalType
,
502 EFI_UNICODE_STRING_TABLE
**ControllerNameTable
506 EFI_UNICODE_STRING_TABLE
*Table
;
508 ASSERT (TerminalType
< ARRAY_SIZE (mTerminalType
));
510 Status
= AddUnicodeString2 (
512 gTerminalComponentName
.SupportedLanguages
,
514 mSerialConsoleNames
[TerminalType
],
517 if (!EFI_ERROR (Status
)) {
518 Status
= AddUnicodeString2 (
520 gTerminalComponentName2
.SupportedLanguages
,
522 mSerialConsoleNames
[TerminalType
],
525 if (EFI_ERROR (Status
)) {
526 FreeUnicodeStringTable (Table
);
529 if (!EFI_ERROR (Status
)) {
530 *ControllerNameTable
= Table
;
536 Start this driver on Controller by opening a Serial IO protocol,
537 reading Device Path, and creating a child handle with a Simple Text In,
538 Simple Text In Ex and Simple Text Out protocol, and device path protocol.
539 And store Console Device Environment Variables.
541 @param This Protocol instance pointer.
542 @param Controller Handle of device to bind driver to
543 @param RemainingDevicePath Optional parameter use to pick a specific child
546 @retval EFI_SUCCESS This driver is added to Controller.
547 @retval EFI_ALREADY_STARTED This driver is already running on Controller.
548 @retval other This driver does not support this device.
553 TerminalDriverBindingStart (
554 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
555 IN EFI_HANDLE Controller
,
556 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
560 EFI_SERIAL_IO_PROTOCOL
*SerialIo
;
561 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
562 VENDOR_DEVICE_PATH
*Node
;
563 EFI_SERIAL_IO_MODE
*Mode
;
564 UINTN SerialInTimeOut
;
565 TERMINAL_DEV
*TerminalDevice
;
566 TERMINAL_TYPE TerminalType
;
567 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
*OpenInfoBuffer
;
570 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
571 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*SimpleTextOutput
;
572 EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*SimpleTextInput
;
573 BOOLEAN ConInSelected
;
574 BOOLEAN ConOutSelected
;
575 BOOLEAN NullRemaining
;
576 BOOLEAN SimTxtInInstalled
;
577 BOOLEAN SimTxtOutInstalled
;
580 TerminalDevice
= NULL
;
581 ConInSelected
= FALSE
;
582 ConOutSelected
= FALSE
;
583 NullRemaining
= FALSE
;
584 SimTxtInInstalled
= FALSE
;
585 SimTxtOutInstalled
= FALSE
;
588 // Get the Device Path Protocol to build the device path of the child device
590 Status
= gBS
->OpenProtocol (
592 &gEfiDevicePathProtocolGuid
,
593 (VOID
**) &ParentDevicePath
,
594 This
->DriverBindingHandle
,
596 EFI_OPEN_PROTOCOL_BY_DRIVER
598 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
603 // Open the Serial I/O Protocol BY_DRIVER. It might already be started.
605 Status
= gBS
->OpenProtocol (
607 &gEfiSerialIoProtocolGuid
,
609 This
->DriverBindingHandle
,
611 EFI_OPEN_PROTOCOL_BY_DRIVER
613 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
617 if (Status
!= EFI_ALREADY_STARTED
) {
619 // the serial I/O protocol never be opened before, it is the first
620 // time to start the serial Io controller
626 // Serial I/O is not already open by this driver, then tag the handle
627 // with the Terminal Driver GUID and update the ConInDev, ConOutDev, and
628 // StdErrDev variables with the list of possible terminal types on this
631 Status
= gBS
->OpenProtocol (
635 This
->DriverBindingHandle
,
637 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
639 if (EFI_ERROR (Status
)) {
640 Status
= gBS
->InstallMultipleProtocolInterfaces (
643 DuplicateDevicePath (ParentDevicePath
),
646 if (EFI_ERROR (Status
)) {
650 if (!IsHotPlugDevice (ParentDevicePath
)) {
652 // if the serial device is a hot plug device, do not update the
653 // ConInDev, ConOutDev, and StdErrDev variables.
655 TerminalUpdateConsoleDevVariable (L
"ConInDev", ParentDevicePath
);
656 TerminalUpdateConsoleDevVariable (L
"ConOutDev", ParentDevicePath
);
657 TerminalUpdateConsoleDevVariable (L
"ErrOutDev", ParentDevicePath
);
662 // Check the requirement for the SimpleTxtIn and SimpleTxtOut protocols
664 // Simple In/Out Protocol will not be installed onto the handle if the
665 // device path to the handle is not present in the ConIn/ConOut
666 // environment variable. But If RemainingDevicePath is NULL, then always
667 // produce both Simple In and Simple Text Output Protocols. This is required
668 // for the connect all sequences to make sure all possible consoles are
669 // produced no matter what the current values of ConIn, ConOut, or StdErr are.
671 if (RemainingDevicePath
== NULL
) {
672 NullRemaining
= TRUE
;
675 DevicePath
= BuildTerminalDevpath (ParentDevicePath
, RemainingDevicePath
);
676 if (DevicePath
!= NULL
) {
677 ConInSelected
= IsTerminalInConsoleVariable (L
"ConIn", DevicePath
);
678 ConOutSelected
= IsTerminalInConsoleVariable (L
"ConOut", DevicePath
);
679 FreePool (DevicePath
);
684 // Not create the child terminal handle if both Simple In/In Ex and
685 // Simple text Out protocols are not required to be published
687 if ((!ConInSelected
)&&(!ConOutSelected
)&&(!NullRemaining
)) {
692 // create the child terminal handle during first entry
696 // First enther the start function
700 // Make sure a child handle does not already exist. This driver can only
701 // produce one child per serial port.
703 Status
= gBS
->OpenProtocolInformation (
705 &gEfiSerialIoProtocolGuid
,
709 if (!EFI_ERROR (Status
)) {
710 Status
= EFI_SUCCESS
;
711 for (Index
= 0; Index
< EntryCount
; Index
++) {
712 if ((OpenInfoBuffer
[Index
].Attributes
& EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
) != 0) {
713 Status
= EFI_ALREADY_STARTED
;
717 FreePool (OpenInfoBuffer
);
718 if (EFI_ERROR (Status
)) {
724 // If RemainingDevicePath is NULL, use default terminal type
726 if (RemainingDevicePath
== NULL
) {
727 TerminalType
= PcdGet8 (PcdDefaultTerminalType
);
728 } else if (!IsDevicePathEnd (RemainingDevicePath
)) {
730 // If RemainingDevicePath isn't the End of Device Path Node,
731 // Use the RemainingDevicePath to determine the terminal type
733 Node
= (VENDOR_DEVICE_PATH
*)RemainingDevicePath
;
734 TerminalType
= TerminalTypeFromGuid (&Node
->Guid
);
737 // If RemainingDevicePath is the End of Device Path Node,
738 // skip enumerate any device and return EFI_SUCESSS
743 ASSERT (TerminalType
< ARRAY_SIZE (mTerminalType
));
746 // Initialize the Terminal Dev
748 TerminalDevice
= AllocateCopyPool (sizeof (TERMINAL_DEV
), &mTerminalDevTemplate
);
749 if (TerminalDevice
== NULL
) {
750 Status
= EFI_OUT_OF_RESOURCES
;
754 TerminalDevice
->TerminalType
= TerminalType
;
755 TerminalDevice
->SerialIo
= SerialIo
;
757 InitializeListHead (&TerminalDevice
->NotifyList
);
758 Status
= gBS
->CreateEvent (
761 TerminalConInWaitForKeyEx
,
763 &TerminalDevice
->SimpleInputEx
.WaitForKeyEx
765 if (EFI_ERROR (Status
)) {
769 Status
= gBS
->CreateEvent (
772 TerminalConInWaitForKey
,
774 &TerminalDevice
->SimpleInput
.WaitForKey
776 if (EFI_ERROR (Status
)) {
780 // Allocates and initializes the FIFO buffer to be zero, used for accommodating
781 // the pre-read pending characters.
783 TerminalDevice
->RawFiFo
= AllocateZeroPool (sizeof (RAW_DATA_FIFO
));
784 if (TerminalDevice
->RawFiFo
== NULL
) {
787 TerminalDevice
->UnicodeFiFo
= AllocateZeroPool (sizeof (UNICODE_FIFO
));
788 if (TerminalDevice
->UnicodeFiFo
== NULL
) {
791 TerminalDevice
->EfiKeyFiFo
= AllocateZeroPool (sizeof (EFI_KEY_FIFO
));
792 if (TerminalDevice
->EfiKeyFiFo
== NULL
) {
795 TerminalDevice
->EfiKeyFiFoForNotify
= AllocateZeroPool (sizeof (EFI_KEY_FIFO
));
796 if (TerminalDevice
->EfiKeyFiFoForNotify
== NULL
) {
801 // Set the timeout value of serial buffer for
802 // keystroke response performance issue
804 Mode
= TerminalDevice
->SerialIo
->Mode
;
807 if (Mode
->BaudRate
!= 0) {
808 SerialInTimeOut
= (1 + Mode
->DataBits
+ Mode
->StopBits
) * 2 * 1000000 / (UINTN
) Mode
->BaudRate
;
811 Status
= TerminalDevice
->SerialIo
->SetAttributes (
812 TerminalDevice
->SerialIo
,
814 Mode
->ReceiveFifoDepth
,
815 (UINT32
) SerialInTimeOut
,
816 (EFI_PARITY_TYPE
) (Mode
->Parity
),
817 (UINT8
) Mode
->DataBits
,
818 (EFI_STOP_BITS_TYPE
) (Mode
->StopBits
)
820 if (EFI_ERROR (Status
)) {
822 // if set attributes operation fails, invalidate
823 // the value of SerialInTimeOut,thus make it
824 // inconsistent with the default timeout value
825 // of serial buffer. This will invoke the recalculation
826 // in the readkeystroke routine.
828 TerminalDevice
->SerialInTimeOut
= 0;
830 TerminalDevice
->SerialInTimeOut
= SerialInTimeOut
;
833 // Set Simple Text Output Protocol from template.
835 SimpleTextOutput
= CopyMem (
836 &TerminalDevice
->SimpleTextOutput
,
837 &mTerminalDevTemplate
.SimpleTextOutput
,
838 sizeof (mTerminalDevTemplate
.SimpleTextOutput
)
840 SimpleTextOutput
->Mode
= &TerminalDevice
->SimpleTextOutputMode
;
842 TerminalDevice
->TerminalConsoleModeData
= InitializeTerminalConsoleTextMode (
843 &SimpleTextOutput
->Mode
->MaxMode
845 if (TerminalDevice
->TerminalConsoleModeData
== NULL
) {
850 // For terminal devices, cursor is always visible
852 TerminalDevice
->SimpleTextOutputMode
.CursorVisible
= TRUE
;
853 Status
= TerminalConOutSetAttribute (
855 EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
)
857 if (EFI_ERROR (Status
)) {
862 // Build the component name for the child device
864 Status
= InitializeControllerNameTable (TerminalDevice
->TerminalType
, &TerminalDevice
->ControllerNameTable
);
865 if (EFI_ERROR (Status
)) {
870 // Build the device path for the child device
872 Status
= SetTerminalDevicePath (
873 TerminalDevice
->TerminalType
,
875 &TerminalDevice
->DevicePath
877 if (EFI_ERROR (Status
)) {
881 Status
= TerminalConOutReset (SimpleTextOutput
, FALSE
);
882 if (EFI_ERROR (Status
)) {
886 Status
= TerminalConOutSetMode (SimpleTextOutput
, 0);
887 if (EFI_ERROR (Status
)) {
891 Status
= TerminalConOutEnableCursor (SimpleTextOutput
, TRUE
);
892 if (EFI_ERROR (Status
)) {
896 Status
= gBS
->CreateEvent (
897 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
899 TerminalConInTimerHandler
,
901 &TerminalDevice
->TimerEvent
903 ASSERT_EFI_ERROR (Status
);
905 Status
= gBS
->SetTimer (
906 TerminalDevice
->TimerEvent
,
908 KEYBOARD_TIMER_INTERVAL
910 ASSERT_EFI_ERROR (Status
);
912 Status
= gBS
->CreateEvent (
917 &TerminalDevice
->TwoSecondTimeOut
919 ASSERT_EFI_ERROR (Status
);
921 Status
= gBS
->CreateEvent (
924 KeyNotifyProcessHandler
,
926 &TerminalDevice
->KeyNotifyProcessEvent
928 ASSERT_EFI_ERROR (Status
);
930 Status
= gBS
->InstallProtocolInterface (
931 &TerminalDevice
->Handle
,
932 &gEfiDevicePathProtocolGuid
,
933 EFI_NATIVE_INTERFACE
,
934 TerminalDevice
->DevicePath
936 if (EFI_ERROR (Status
)) {
941 // Register the Parent-Child relationship via
942 // EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
944 Status
= gBS
->OpenProtocol (
946 &gEfiSerialIoProtocolGuid
,
947 (VOID
**) &TerminalDevice
->SerialIo
,
948 This
->DriverBindingHandle
,
949 TerminalDevice
->Handle
,
950 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
952 if (EFI_ERROR (Status
)) {
958 // Find the child handle, and get its TerminalDevice private data
960 Status
= gBS
->OpenProtocolInformation (
962 &gEfiSerialIoProtocolGuid
,
966 if (!EFI_ERROR (Status
)) {
967 Status
= EFI_NOT_FOUND
;
968 ASSERT (OpenInfoBuffer
!= NULL
);
969 for (Index
= 0; Index
< EntryCount
; Index
++) {
970 if ((OpenInfoBuffer
[Index
].Attributes
& EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
) != 0) {
972 // Find the child terminal handle.
973 // Test whether the SimpleTxtIn and SimpleTxtOut have been published
975 Status
= gBS
->OpenProtocol (
976 OpenInfoBuffer
[Index
].ControllerHandle
,
977 &gEfiSimpleTextInProtocolGuid
,
978 (VOID
**) &SimpleTextInput
,
979 This
->DriverBindingHandle
,
980 OpenInfoBuffer
[Index
].ControllerHandle
,
981 EFI_OPEN_PROTOCOL_GET_PROTOCOL
983 if (!EFI_ERROR (Status
)) {
984 SimTxtInInstalled
= TRUE
;
985 TerminalDevice
= TERMINAL_CON_IN_DEV_FROM_THIS (SimpleTextInput
);
988 Status
= gBS
->OpenProtocol (
989 OpenInfoBuffer
[Index
].ControllerHandle
,
990 &gEfiSimpleTextOutProtocolGuid
,
991 (VOID
**) &SimpleTextOutput
,
992 This
->DriverBindingHandle
,
993 OpenInfoBuffer
[Index
].ControllerHandle
,
994 EFI_OPEN_PROTOCOL_GET_PROTOCOL
996 if (!EFI_ERROR (Status
)) {
997 SimTxtOutInstalled
= TRUE
;
998 TerminalDevice
= TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput
);
1000 Status
= EFI_SUCCESS
;
1005 FreePool (OpenInfoBuffer
);
1006 if (EFI_ERROR (Status
)) {
1013 ASSERT (TerminalDevice
!= NULL
);
1015 // Only do the reset if the device path is in the Conout variable
1017 if (ConInSelected
&& !SimTxtInInstalled
) {
1018 Status
= TerminalDevice
->SimpleInput
.Reset (
1019 &TerminalDevice
->SimpleInput
,
1022 if (EFI_ERROR (Status
)) {
1024 // Need to report Error Code first
1031 // Only output the configure string to remote terminal if the device path
1032 // is in the Conout variable
1034 if (ConOutSelected
&& !SimTxtOutInstalled
) {
1035 Status
= TerminalDevice
->SimpleTextOutput
.SetAttribute (
1036 &TerminalDevice
->SimpleTextOutput
,
1037 EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
)
1039 if (EFI_ERROR (Status
)) {
1043 Status
= TerminalDevice
->SimpleTextOutput
.Reset (
1044 &TerminalDevice
->SimpleTextOutput
,
1047 if (EFI_ERROR (Status
)) {
1051 Status
= TerminalDevice
->SimpleTextOutput
.SetMode (
1052 &TerminalDevice
->SimpleTextOutput
,
1055 if (EFI_ERROR (Status
)) {
1059 Status
= TerminalDevice
->SimpleTextOutput
.EnableCursor (
1060 &TerminalDevice
->SimpleTextOutput
,
1063 if (EFI_ERROR (Status
)) {
1069 // Simple In/Out Protocol will not be installed onto the handle if the
1070 // device path to the handle is not present in the ConIn/ConOut
1071 // environment variable. But If RemainingDevicePath is NULL, then always
1072 // produce both Simple In and Simple Text Output Protocols. This is required
1073 // for the connect all sequences to make sure all possible consoles are
1074 // produced no matter what the current values of ConIn, ConOut, or StdErr are.
1076 if (!SimTxtInInstalled
&& (ConInSelected
|| NullRemaining
)) {
1077 Status
= gBS
->InstallMultipleProtocolInterfaces (
1078 &TerminalDevice
->Handle
,
1079 &gEfiSimpleTextInProtocolGuid
,
1080 &TerminalDevice
->SimpleInput
,
1081 &gEfiSimpleTextInputExProtocolGuid
,
1082 &TerminalDevice
->SimpleInputEx
,
1085 if (EFI_ERROR (Status
)) {
1090 if (!SimTxtOutInstalled
&& (ConOutSelected
|| NullRemaining
)) {
1091 Status
= gBS
->InstallProtocolInterface (
1092 &TerminalDevice
->Handle
,
1093 &gEfiSimpleTextOutProtocolGuid
,
1094 EFI_NATIVE_INTERFACE
,
1095 &TerminalDevice
->SimpleTextOutput
1097 if (EFI_ERROR (Status
)) {
1106 // Report error code before exiting
1108 DevicePath
= ParentDevicePath
;
1109 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1110 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1111 (EFI_PERIPHERAL_REMOTE_CONSOLE
| EFI_P_EC_CONTROLLER_ERROR
),
1117 // Use the Stop() function to free all resources allocated in Start()
1119 if (TerminalDevice
!= NULL
) {
1121 if (TerminalDevice
->Handle
!= NULL
) {
1122 This
->Stop (This
, Controller
, 1, &TerminalDevice
->Handle
);
1125 if (TerminalDevice
->TwoSecondTimeOut
!= NULL
) {
1126 gBS
->CloseEvent (TerminalDevice
->TwoSecondTimeOut
);
1129 if (TerminalDevice
->TimerEvent
!= NULL
) {
1130 gBS
->CloseEvent (TerminalDevice
->TimerEvent
);
1133 if (TerminalDevice
->SimpleInput
.WaitForKey
!= NULL
) {
1134 gBS
->CloseEvent (TerminalDevice
->SimpleInput
.WaitForKey
);
1137 if (TerminalDevice
->SimpleInputEx
.WaitForKeyEx
!= NULL
) {
1138 gBS
->CloseEvent (TerminalDevice
->SimpleInputEx
.WaitForKeyEx
);
1141 TerminalFreeNotifyList (&TerminalDevice
->NotifyList
);
1143 if (TerminalDevice
->RawFiFo
!= NULL
) {
1144 FreePool (TerminalDevice
->RawFiFo
);
1146 if (TerminalDevice
->UnicodeFiFo
!= NULL
) {
1147 FreePool (TerminalDevice
->UnicodeFiFo
);
1149 if (TerminalDevice
->EfiKeyFiFo
!= NULL
) {
1150 FreePool (TerminalDevice
->EfiKeyFiFo
);
1152 if (TerminalDevice
->EfiKeyFiFoForNotify
!= NULL
) {
1153 FreePool (TerminalDevice
->EfiKeyFiFoForNotify
);
1156 if (TerminalDevice
->ControllerNameTable
!= NULL
) {
1157 FreeUnicodeStringTable (TerminalDevice
->ControllerNameTable
);
1160 if (TerminalDevice
->DevicePath
!= NULL
) {
1161 FreePool (TerminalDevice
->DevicePath
);
1164 if (TerminalDevice
->TerminalConsoleModeData
!= NULL
) {
1165 FreePool (TerminalDevice
->TerminalConsoleModeData
);
1168 FreePool (TerminalDevice
);
1172 This
->Stop (This
, Controller
, 0, NULL
);
1178 Stop this driver on Controller by closing Simple Text In, Simple Text
1179 In Ex, Simple Text Out protocol, and removing parent device path from
1180 Console Device Environment Variables.
1182 @param This Protocol instance pointer.
1183 @param Controller Handle of device to stop driver on
1184 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
1185 children is zero stop the entire bus driver.
1186 @param ChildHandleBuffer List of Child Handles to Stop.
1188 @retval EFI_SUCCESS This driver is removed Controller.
1189 @retval other This driver could not be removed from this device.
1194 TerminalDriverBindingStop (
1195 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1196 IN EFI_HANDLE Controller
,
1197 IN UINTN NumberOfChildren
,
1198 IN EFI_HANDLE
*ChildHandleBuffer
1203 BOOLEAN AllChildrenStopped
;
1204 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*SimpleTextOutput
;
1205 TERMINAL_DEV
*TerminalDevice
;
1206 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
1207 EFI_SERIAL_IO_PROTOCOL
*SerialIo
;
1208 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1210 Status
= gBS
->HandleProtocol (
1212 &gEfiDevicePathProtocolGuid
,
1213 (VOID
**) &DevicePath
1215 if (EFI_ERROR (Status
)) {
1220 // Complete all outstanding transactions to Controller.
1221 // Don't allow any new transaction to Controller to be started.
1223 if (NumberOfChildren
== 0) {
1225 // Close the bus driver
1227 Status
= gBS
->OpenProtocol (
1230 (VOID
**) &ParentDevicePath
,
1231 This
->DriverBindingHandle
,
1233 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1235 if (!EFI_ERROR (Status
)) {
1237 // Remove Parent Device Path from
1238 // the Console Device Environment Variables
1240 TerminalRemoveConsoleDevVariable (L
"ConInDev", ParentDevicePath
);
1241 TerminalRemoveConsoleDevVariable (L
"ConOutDev", ParentDevicePath
);
1242 TerminalRemoveConsoleDevVariable (L
"ErrOutDev", ParentDevicePath
);
1245 // Uninstall the Terminal Driver's GUID Tag from the Serial controller
1247 Status
= gBS
->UninstallMultipleProtocolInterfaces (
1255 // Free the ParentDevicePath that was duplicated in Start()
1257 if (!EFI_ERROR (Status
)) {
1258 FreePool (ParentDevicePath
);
1262 gBS
->CloseProtocol (
1264 &gEfiSerialIoProtocolGuid
,
1265 This
->DriverBindingHandle
,
1269 gBS
->CloseProtocol (
1271 &gEfiDevicePathProtocolGuid
,
1272 This
->DriverBindingHandle
,
1279 AllChildrenStopped
= TRUE
;
1281 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
1283 Status
= gBS
->OpenProtocol (
1284 ChildHandleBuffer
[Index
],
1285 &gEfiSimpleTextOutProtocolGuid
,
1286 (VOID
**) &SimpleTextOutput
,
1287 This
->DriverBindingHandle
,
1288 ChildHandleBuffer
[Index
],
1289 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1291 if (!EFI_ERROR (Status
)) {
1293 TerminalDevice
= TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput
);
1295 gBS
->CloseProtocol (
1297 &gEfiSerialIoProtocolGuid
,
1298 This
->DriverBindingHandle
,
1299 ChildHandleBuffer
[Index
]
1302 Status
= gBS
->UninstallMultipleProtocolInterfaces (
1303 ChildHandleBuffer
[Index
],
1304 &gEfiSimpleTextInProtocolGuid
,
1305 &TerminalDevice
->SimpleInput
,
1306 &gEfiSimpleTextInputExProtocolGuid
,
1307 &TerminalDevice
->SimpleInputEx
,
1308 &gEfiSimpleTextOutProtocolGuid
,
1309 &TerminalDevice
->SimpleTextOutput
,
1310 &gEfiDevicePathProtocolGuid
,
1311 TerminalDevice
->DevicePath
,
1314 if (EFI_ERROR (Status
)) {
1317 &gEfiSerialIoProtocolGuid
,
1318 (VOID
**) &SerialIo
,
1319 This
->DriverBindingHandle
,
1320 ChildHandleBuffer
[Index
],
1321 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1325 if (TerminalDevice
->ControllerNameTable
!= NULL
) {
1326 FreeUnicodeStringTable (TerminalDevice
->ControllerNameTable
);
1329 gBS
->CloseEvent (TerminalDevice
->TimerEvent
);
1330 gBS
->CloseEvent (TerminalDevice
->TwoSecondTimeOut
);
1331 gBS
->CloseEvent (TerminalDevice
->SimpleInput
.WaitForKey
);
1332 gBS
->CloseEvent (TerminalDevice
->SimpleInputEx
.WaitForKeyEx
);
1333 gBS
->CloseEvent (TerminalDevice
->KeyNotifyProcessEvent
);
1334 TerminalFreeNotifyList (&TerminalDevice
->NotifyList
);
1335 FreePool (TerminalDevice
->DevicePath
);
1336 if (TerminalDevice
->TerminalConsoleModeData
!= NULL
) {
1337 FreePool (TerminalDevice
->TerminalConsoleModeData
);
1339 FreePool (TerminalDevice
);
1343 if (EFI_ERROR (Status
)) {
1344 AllChildrenStopped
= FALSE
;
1348 if (!AllChildrenStopped
) {
1349 return EFI_DEVICE_ERROR
;
1356 Update terminal device path in Console Device Environment Variables.
1358 @param VariableName The Console Device Environment Variable.
1359 @param ParentDevicePath The terminal device path to be updated.
1363 TerminalUpdateConsoleDevVariable (
1364 IN CHAR16
*VariableName
,
1365 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
1371 TERMINAL_TYPE TerminalType
;
1372 EFI_DEVICE_PATH_PROTOCOL
*Variable
;
1373 EFI_DEVICE_PATH_PROTOCOL
*NewVariable
;
1374 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1375 EDKII_SET_VARIABLE_STATUS
*SetVariableStatus
;
1378 // Get global variable and its size according to the name given.
1380 GetEfiGlobalVariable2 (VariableName
, (VOID
**)&Variable
, NULL
);
1381 if (Variable
== NULL
) {
1386 // Append terminal device path onto the variable.
1388 for (TerminalType
= 0; TerminalType
< ARRAY_SIZE (mTerminalType
); TerminalType
++) {
1389 SetTerminalDevicePath (TerminalType
, ParentDevicePath
, &TempDevicePath
);
1390 NewVariable
= AppendDevicePathInstance (Variable
, TempDevicePath
);
1391 ASSERT (NewVariable
!= NULL
);
1392 if (Variable
!= NULL
) {
1393 FreePool (Variable
);
1396 if (TempDevicePath
!= NULL
) {
1397 FreePool (TempDevicePath
);
1400 Variable
= NewVariable
;
1403 VariableSize
= GetDevicePathSize (Variable
);
1405 Status
= gRT
->SetVariable (
1407 &gEfiGlobalVariableGuid
,
1408 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1413 if (EFI_ERROR (Status
)) {
1414 NameSize
= StrSize (VariableName
);
1415 SetVariableStatus
= AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS
) + NameSize
+ VariableSize
);
1416 if (SetVariableStatus
!= NULL
) {
1417 CopyGuid (&SetVariableStatus
->Guid
, &gEfiGlobalVariableGuid
);
1418 SetVariableStatus
->NameSize
= NameSize
;
1419 SetVariableStatus
->DataSize
= VariableSize
;
1420 SetVariableStatus
->SetStatus
= Status
;
1421 SetVariableStatus
->Attributes
= EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
;
1422 CopyMem (SetVariableStatus
+ 1, VariableName
, NameSize
);
1423 CopyMem (((UINT8
*) (SetVariableStatus
+ 1)) + NameSize
, Variable
, VariableSize
);
1425 REPORT_STATUS_CODE_EX (
1427 PcdGet32 (PcdErrorCodeSetVariable
),
1430 &gEdkiiStatusCodeDataTypeVariableGuid
,
1432 sizeof (EDKII_SET_VARIABLE_STATUS
) + NameSize
+ VariableSize
1435 FreePool (SetVariableStatus
);
1439 FreePool (Variable
);
1446 Remove terminal device path from Console Device Environment Variables.
1448 @param VariableName Console Device Environment Variables.
1449 @param ParentDevicePath The terminal device path to be updated.
1453 TerminalRemoveConsoleDevVariable (
1454 IN CHAR16
*VariableName
,
1455 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
1463 TERMINAL_TYPE TerminalType
;
1464 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
1465 EFI_DEVICE_PATH_PROTOCOL
*Variable
;
1466 EFI_DEVICE_PATH_PROTOCOL
*OriginalVariable
;
1467 EFI_DEVICE_PATH_PROTOCOL
*NewVariable
;
1468 EFI_DEVICE_PATH_PROTOCOL
*SavedNewVariable
;
1469 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1474 // Get global variable and its size according to the name given.
1476 GetEfiGlobalVariable2 (VariableName
, (VOID
**)&Variable
, NULL
);
1477 if (Variable
== NULL
) {
1482 OriginalVariable
= Variable
;
1486 // Get first device path instance from Variable
1488 Instance
= GetNextDevicePathInstance (&Variable
, &InstanceSize
);
1489 if (Instance
== NULL
) {
1490 FreePool (OriginalVariable
);
1494 // Loop through all the device path instances of Variable
1498 // Loop through all the terminal types that this driver supports
1501 for (TerminalType
= 0; TerminalType
< ARRAY_SIZE (mTerminalType
); TerminalType
++) {
1503 SetTerminalDevicePath (TerminalType
, ParentDevicePath
, &TempDevicePath
);
1506 // Compare the generated device path to the current device path instance
1508 if (TempDevicePath
!= NULL
) {
1509 if (CompareMem (Instance
, TempDevicePath
, InstanceSize
) == 0) {
1514 FreePool (TempDevicePath
);
1518 // If a match was not found, then keep the current device path instance
1521 SavedNewVariable
= NewVariable
;
1522 NewVariable
= AppendDevicePathInstance (NewVariable
, Instance
);
1523 if (SavedNewVariable
!= NULL
) {
1524 FreePool (SavedNewVariable
);
1528 // Get next device path instance from Variable
1530 FreePool (Instance
);
1531 Instance
= GetNextDevicePathInstance (&Variable
, &InstanceSize
);
1532 } while (Instance
!= NULL
);
1534 FreePool (OriginalVariable
);
1537 VariableSize
= GetDevicePathSize (NewVariable
);
1539 Status
= gRT
->SetVariable (
1541 &gEfiGlobalVariableGuid
,
1542 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1547 // Shrinking variable with existing variable driver implementation shouldn't fail.
1549 ASSERT_EFI_ERROR (Status
);
1552 if (NewVariable
!= NULL
) {
1553 FreePool (NewVariable
);
1560 Build terminal device path according to terminal type.
1562 @param TerminalType The terminal type is PC ANSI, VT100, VT100+ or VT-UTF8.
1563 @param ParentDevicePath Parent device path.
1564 @param TerminalDevicePath Returned terminal device path, if building successfully.
1566 @retval EFI_UNSUPPORTED Terminal does not belong to the supported type.
1567 @retval EFI_OUT_OF_RESOURCES Generate terminal device path failed.
1568 @retval EFI_SUCCESS Build terminal device path successfully.
1572 SetTerminalDevicePath (
1573 IN TERMINAL_TYPE TerminalType
,
1574 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
1575 OUT EFI_DEVICE_PATH_PROTOCOL
**TerminalDevicePath
1578 VENDOR_DEVICE_PATH Node
;
1580 ASSERT (TerminalType
< ARRAY_SIZE (mTerminalType
));
1581 Node
.Header
.Type
= MESSAGING_DEVICE_PATH
;
1582 Node
.Header
.SubType
= MSG_VENDOR_DP
;
1583 SetDevicePathNodeLength (&Node
, sizeof (VENDOR_DEVICE_PATH
));
1584 CopyGuid (&Node
.Guid
, mTerminalType
[TerminalType
]);
1587 // Append the terminal node onto parent device path
1588 // to generate a complete terminal device path.
1590 *TerminalDevicePath
= AppendDevicePathNode (
1592 (EFI_DEVICE_PATH_PROTOCOL
*) &Node
1594 if (*TerminalDevicePath
== NULL
) {
1595 return EFI_OUT_OF_RESOURCES
;
1602 The user Entry Point for module Terminal. The user code starts with this function.
1604 @param ImageHandle The firmware allocated handle for the EFI image.
1605 @param SystemTable A pointer to the EFI System Table.
1607 @retval EFI_SUCCESS The entry point is executed successfully.
1608 @retval other Some error occurs when executing this entry point.
1614 IN EFI_HANDLE ImageHandle
,
1615 IN EFI_SYSTEM_TABLE
*SystemTable
1621 // Install driver model protocol(s).
1623 Status
= EfiLibInstallDriverBindingComponentName2 (
1626 &gTerminalDriverBinding
,
1628 &gTerminalComponentName
,
1629 &gTerminalComponentName2
1631 ASSERT_EFI_ERROR (Status
);
1637 Check if the device supports hot-plug through its device path.
1639 This function could be updated to check more types of Hot Plug devices.
1640 Currently, it checks USB and PCCard device.
1642 @param DevicePath Pointer to device's device path.
1644 @retval TRUE The devcie is a hot-plug device
1645 @retval FALSE The devcie is not a hot-plug device.
1650 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1653 EFI_DEVICE_PATH_PROTOCOL
*CheckDevicePath
;
1655 CheckDevicePath
= DevicePath
;
1656 while (!IsDevicePathEnd (CheckDevicePath
)) {
1658 // Check device whether is hot plug device or not throught Device Path
1660 if ((DevicePathType (CheckDevicePath
) == MESSAGING_DEVICE_PATH
) &&
1661 (DevicePathSubType (CheckDevicePath
) == MSG_USB_DP
||
1662 DevicePathSubType (CheckDevicePath
) == MSG_USB_CLASS_DP
||
1663 DevicePathSubType (CheckDevicePath
) == MSG_USB_WWID_DP
)) {
1665 // If Device is USB device
1669 if ((DevicePathType (CheckDevicePath
) == HARDWARE_DEVICE_PATH
) &&
1670 (DevicePathSubType (CheckDevicePath
) == HW_PCCARD_DP
)) {
1672 // If Device is PCCard
1677 CheckDevicePath
= NextDevicePathNode (CheckDevicePath
);