]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
MdeModulePkg: Apply uncrustify changes
[mirror_edk2.git] / MdeModulePkg / Universal / Console / TerminalDxe / Terminal.c
1 /** @file
2 Produces Simple Text Input Protocol, Simple Text Input Extended Protocol and
3 Simple Text Output Protocol upon Serial IO Protocol.
4
5 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "Terminal.h"
11
12 //
13 // Globals
14 //
15 EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding = {
16 TerminalDriverBindingSupported,
17 TerminalDriverBindingStart,
18 TerminalDriverBindingStop,
19 0xa,
20 NULL,
21 NULL
22 };
23
24 EFI_GUID *mTerminalType[] = {
25 &gEfiPcAnsiGuid,
26 &gEfiVT100Guid,
27 &gEfiVT100PlusGuid,
28 &gEfiVTUTF8Guid,
29 &gEfiTtyTermGuid,
30 &gEdkiiLinuxTermGuid,
31 &gEdkiiXtermR6Guid,
32 &gEdkiiVT400Guid,
33 &gEdkiiSCOTermGuid
34 };
35
36 CHAR16 *mSerialConsoleNames[] = {
37 L"PC-ANSI Serial Console",
38 L"VT-100 Serial Console",
39 L"VT-100+ Serial Console",
40 L"VT-UTF8 Serial Console",
41 L"Tty Terminal Serial Console",
42 L"Linux Terminal Serial Console",
43 L"Xterm R6 Serial Console",
44 L"VT-400 Serial Console",
45 L"SCO Terminal Serial Console"
46 };
47
48 TERMINAL_DEV mTerminalDevTemplate = {
49 TERMINAL_DEV_SIGNATURE,
50 NULL,
51 0,
52 NULL,
53 NULL,
54 { // SimpleTextInput
55 TerminalConInReset,
56 TerminalConInReadKeyStroke,
57 NULL
58 },
59 { // SimpleTextOutput
60 TerminalConOutReset,
61 TerminalConOutOutputString,
62 TerminalConOutTestString,
63 TerminalConOutQueryMode,
64 TerminalConOutSetMode,
65 TerminalConOutSetAttribute,
66 TerminalConOutClearScreen,
67 TerminalConOutSetCursorPosition,
68 TerminalConOutEnableCursor,
69 NULL
70 },
71 { // SimpleTextOutputMode
72 1, // MaxMode
73 0, // Mode
74 EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK), // Attribute
75 0, // CursorColumn
76 0, // CursorRow
77 TRUE // CursorVisible
78 },
79 NULL, // TerminalConsoleModeData
80 0, // SerialInTimeOut
81
82 NULL, // RawFifo
83 NULL, // UnicodeFiFo
84 NULL, // EfiKeyFiFo
85 NULL, // EfiKeyFiFoForNotify
86
87 NULL, // ControllerNameTable
88 NULL, // TimerEvent
89 NULL, // TwoSecondTimeOut
90 INPUT_STATE_DEFAULT,
91 RESET_STATE_DEFAULT,
92 {
93 0,
94 0,
95 0
96 },
97 0,
98 FALSE,
99 { // SimpleTextInputEx
100 TerminalConInResetEx,
101 TerminalConInReadKeyStrokeEx,
102 NULL,
103 TerminalConInSetState,
104 TerminalConInRegisterKeyNotify,
105 TerminalConInUnregisterKeyNotify,
106 },
107 { // NotifyList
108 NULL,
109 NULL,
110 },
111 NULL // KeyNotifyProcessEvent
112 };
113
114 TERMINAL_CONSOLE_MODE_DATA mTerminalConsoleModeData[] = {
115 { 80, 25 },
116 { 80, 50 },
117 { 100, 31 },
118 //
119 // New modes can be added here.
120 //
121 };
122
123 /**
124 Convert the GUID representation of terminal type to enum type.
125
126 @param Guid The GUID representation of terminal type.
127
128 @return The terminal type in enum type.
129 **/
130 TERMINAL_TYPE
131 TerminalTypeFromGuid (
132 IN EFI_GUID *Guid
133 )
134 {
135 TERMINAL_TYPE Type;
136
137 for (Type = 0; Type < ARRAY_SIZE (mTerminalType); Type++) {
138 if (CompareGuid (Guid, mTerminalType[Type])) {
139 break;
140 }
141 }
142
143 return Type;
144 }
145
146 /**
147 Test to see if this driver supports Controller.
148
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
152 device to start.
153
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.
157
158 **/
159 EFI_STATUS
160 EFIAPI
161 TerminalDriverBindingSupported (
162 IN EFI_DRIVER_BINDING_PROTOCOL *This,
163 IN EFI_HANDLE Controller,
164 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
165 )
166 {
167 EFI_STATUS Status;
168 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
169 EFI_SERIAL_IO_PROTOCOL *SerialIo;
170 VENDOR_DEVICE_PATH *Node;
171
172 //
173 // If remaining device path is not NULL, then make sure it is a
174 // device path that describes a terminal communications protocol.
175 //
176 if (RemainingDevicePath != NULL) {
177 //
178 // Check if RemainingDevicePath is the End of Device Path Node,
179 // if yes, go on checking other conditions
180 //
181 if (!IsDevicePathEnd (RemainingDevicePath)) {
182 //
183 // If RemainingDevicePath isn't the End of Device Path Node,
184 // check its validation
185 //
186 Node = (VENDOR_DEVICE_PATH *)RemainingDevicePath;
187
188 if ((Node->Header.Type != MESSAGING_DEVICE_PATH) ||
189 (Node->Header.SubType != MSG_VENDOR_DP) ||
190 (DevicePathNodeLength (&Node->Header) != sizeof (VENDOR_DEVICE_PATH)))
191 {
192 return EFI_UNSUPPORTED;
193 }
194
195 //
196 // only supports PC ANSI, VT100, VT100+, VT-UTF8, TtyTerm
197 // Linux, XtermR6, VT400 and SCO terminal types
198 //
199 if (TerminalTypeFromGuid (&Node->Guid) == ARRAY_SIZE (mTerminalType)) {
200 return EFI_UNSUPPORTED;
201 }
202 }
203 }
204
205 //
206 // Open the IO Abstraction(s) needed to perform the supported test
207 // The Controller must support the Serial I/O Protocol.
208 // This driver is a bus driver with at most 1 child device, so it is
209 // ok for it to be already started.
210 //
211 Status = gBS->OpenProtocol (
212 Controller,
213 &gEfiSerialIoProtocolGuid,
214 (VOID **)&SerialIo,
215 This->DriverBindingHandle,
216 Controller,
217 EFI_OPEN_PROTOCOL_BY_DRIVER
218 );
219 if (Status == EFI_ALREADY_STARTED) {
220 return EFI_SUCCESS;
221 }
222
223 if (EFI_ERROR (Status)) {
224 return Status;
225 }
226
227 //
228 // Close the I/O Abstraction(s) used to perform the supported test
229 //
230 gBS->CloseProtocol (
231 Controller,
232 &gEfiSerialIoProtocolGuid,
233 This->DriverBindingHandle,
234 Controller
235 );
236
237 //
238 // Open the EFI Device Path protocol needed to perform the supported test
239 //
240 Status = gBS->OpenProtocol (
241 Controller,
242 &gEfiDevicePathProtocolGuid,
243 (VOID **)&ParentDevicePath,
244 This->DriverBindingHandle,
245 Controller,
246 EFI_OPEN_PROTOCOL_BY_DRIVER
247 );
248 if (Status == EFI_ALREADY_STARTED) {
249 return EFI_SUCCESS;
250 }
251
252 if (EFI_ERROR (Status)) {
253 return Status;
254 }
255
256 //
257 // Close protocol, don't use device path protocol in the Support() function
258 //
259 gBS->CloseProtocol (
260 Controller,
261 &gEfiDevicePathProtocolGuid,
262 This->DriverBindingHandle,
263 Controller
264 );
265
266 return Status;
267 }
268
269 /**
270 Free notify functions list.
271
272 @param ListHead The list head
273
274 @retval EFI_SUCCESS Free the notify list successfully.
275 @retval EFI_INVALID_PARAMETER ListHead is NULL.
276
277 **/
278 EFI_STATUS
279 TerminalFreeNotifyList (
280 IN OUT LIST_ENTRY *ListHead
281 )
282 {
283 TERMINAL_CONSOLE_IN_EX_NOTIFY *NotifyNode;
284
285 if (ListHead == NULL) {
286 return EFI_INVALID_PARAMETER;
287 }
288
289 while (!IsListEmpty (ListHead)) {
290 NotifyNode = CR (
291 ListHead->ForwardLink,
292 TERMINAL_CONSOLE_IN_EX_NOTIFY,
293 NotifyEntry,
294 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
295 );
296 RemoveEntryList (ListHead->ForwardLink);
297 FreePool (NotifyNode);
298 }
299
300 return EFI_SUCCESS;
301 }
302
303 /**
304 Initialize all the text modes which the terminal console supports.
305
306 It returns information for available text modes that the terminal can support.
307
308 @param[out] TextModeCount The total number of text modes that terminal console supports.
309
310 @return The buffer to the text modes column and row information.
311 Caller is responsible to free it when it's non-NULL.
312
313 **/
314 TERMINAL_CONSOLE_MODE_DATA *
315 InitializeTerminalConsoleTextMode (
316 OUT INT32 *TextModeCount
317 )
318 {
319 TERMINAL_CONSOLE_MODE_DATA *TextModeData;
320
321 ASSERT (TextModeCount != NULL);
322
323 TextModeData = AllocateCopyPool (sizeof (mTerminalConsoleModeData), mTerminalConsoleModeData);
324 if (TextModeData == NULL) {
325 return NULL;
326 }
327
328 *TextModeCount = ARRAY_SIZE (mTerminalConsoleModeData);
329
330 DEBUG_CODE_BEGIN ();
331 INT32 Index;
332
333 for (Index = 0; Index < *TextModeCount; Index++) {
334 DEBUG ((
335 DEBUG_INFO,
336 "Terminal - Mode %d, Column = %d, Row = %d\n",
337 Index,
338 TextModeData[Index].Columns,
339 TextModeData[Index].Rows
340 ));
341 }
342
343 DEBUG_CODE_END ();
344 return TextModeData;
345 }
346
347 /**
348 Stop the terminal state machine.
349
350 @param TerminalDevice The terminal device.
351 **/
352 VOID
353 StopTerminalStateMachine (
354 TERMINAL_DEV *TerminalDevice
355 )
356 {
357 EFI_TPL OriginalTpl;
358
359 OriginalTpl = gBS->RaiseTPL (TPL_NOTIFY);
360
361 gBS->CloseEvent (TerminalDevice->TimerEvent);
362 gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);
363
364 gBS->RestoreTPL (OriginalTpl);
365 }
366
367 /**
368 Start the terminal state machine.
369
370 @param TerminalDevice The terminal device.
371 **/
372 VOID
373 StartTerminalStateMachine (
374 TERMINAL_DEV *TerminalDevice
375 )
376 {
377 EFI_STATUS Status;
378
379 Status = gBS->CreateEvent (
380 EVT_TIMER | EVT_NOTIFY_SIGNAL,
381 TPL_NOTIFY,
382 TerminalConInTimerHandler,
383 TerminalDevice,
384 &TerminalDevice->TimerEvent
385 );
386 ASSERT_EFI_ERROR (Status);
387
388 Status = gBS->SetTimer (
389 TerminalDevice->TimerEvent,
390 TimerPeriodic,
391 KEYBOARD_TIMER_INTERVAL
392 );
393 ASSERT_EFI_ERROR (Status);
394
395 Status = gBS->CreateEvent (
396 EVT_TIMER,
397 TPL_CALLBACK,
398 NULL,
399 NULL,
400 &TerminalDevice->TwoSecondTimeOut
401 );
402 ASSERT_EFI_ERROR (Status);
403 }
404
405 /**
406 Initialize the controller name table.
407
408 @param TerminalType The terminal type.
409 @param ControllerNameTable The controller name table.
410
411 @retval EFI_SUCCESS The controller name table is initialized successfully.
412 @retval others Return status of AddUnicodeString2 ().
413 **/
414 EFI_STATUS
415 InitializeControllerNameTable (
416 TERMINAL_TYPE TerminalType,
417 EFI_UNICODE_STRING_TABLE **ControllerNameTable
418 )
419 {
420 EFI_STATUS Status;
421 EFI_UNICODE_STRING_TABLE *Table;
422
423 ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));
424 Table = NULL;
425 Status = AddUnicodeString2 (
426 "eng",
427 gTerminalComponentName.SupportedLanguages,
428 &Table,
429 mSerialConsoleNames[TerminalType],
430 TRUE
431 );
432 if (!EFI_ERROR (Status)) {
433 Status = AddUnicodeString2 (
434 "en",
435 gTerminalComponentName2.SupportedLanguages,
436 &Table,
437 mSerialConsoleNames[TerminalType],
438 FALSE
439 );
440 if (EFI_ERROR (Status)) {
441 FreeUnicodeStringTable (Table);
442 }
443 }
444
445 if (!EFI_ERROR (Status)) {
446 *ControllerNameTable = Table;
447 }
448
449 return Status;
450 }
451
452 /**
453 Start this driver on Controller by opening a Serial IO protocol,
454 reading Device Path, and creating a child handle with a Simple Text In,
455 Simple Text In Ex and Simple Text Out protocol, and device path protocol.
456 And store Console Device Environment Variables.
457
458 @param This Protocol instance pointer.
459 @param Controller Handle of device to bind driver to
460 @param RemainingDevicePath Optional parameter use to pick a specific child
461 device to start.
462
463 @retval EFI_SUCCESS This driver is added to Controller.
464 @retval EFI_ALREADY_STARTED This driver is already running on Controller.
465 @retval other This driver does not support this device.
466
467 **/
468 EFI_STATUS
469 EFIAPI
470 TerminalDriverBindingStart (
471 IN EFI_DRIVER_BINDING_PROTOCOL *This,
472 IN EFI_HANDLE Controller,
473 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
474 )
475 {
476 EFI_STATUS Status;
477 EFI_SERIAL_IO_PROTOCOL *SerialIo;
478 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
479 EFI_DEVICE_PATH_PROTOCOL *Vendor;
480 EFI_HANDLE SerialIoHandle;
481 EFI_SERIAL_IO_MODE *Mode;
482 UINTN SerialInTimeOut;
483 TERMINAL_DEV *TerminalDevice;
484 UINT8 TerminalType;
485 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
486 UINTN EntryCount;
487 UINTN Index;
488 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;
489 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextInput;
490 EFI_UNICODE_STRING_TABLE *ControllerNameTable;
491
492 //
493 // Get the Device Path Protocol to build the device path of the child device
494 //
495 Status = gBS->OpenProtocol (
496 Controller,
497 &gEfiDevicePathProtocolGuid,
498 (VOID **)&ParentDevicePath,
499 This->DriverBindingHandle,
500 Controller,
501 EFI_OPEN_PROTOCOL_BY_DRIVER
502 );
503 ASSERT ((Status == EFI_SUCCESS) || (Status == EFI_ALREADY_STARTED));
504 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
505 return Status;
506 }
507
508 //
509 // Open the Serial I/O Protocol BY_DRIVER. It might already be started.
510 //
511 Status = gBS->OpenProtocol (
512 Controller,
513 &gEfiSerialIoProtocolGuid,
514 (VOID **)&SerialIo,
515 This->DriverBindingHandle,
516 Controller,
517 EFI_OPEN_PROTOCOL_BY_DRIVER
518 );
519 ASSERT ((Status == EFI_SUCCESS) || (Status == EFI_ALREADY_STARTED));
520 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
521 return Status;
522 }
523
524 if (!IsHotPlugDevice (ParentDevicePath)) {
525 //
526 // if the serial device is a hot plug device, do not update the
527 // ConInDev, ConOutDev, and StdErrDev variables.
528 //
529 TerminalUpdateConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME, ParentDevicePath);
530 TerminalUpdateConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
531 TerminalUpdateConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
532 }
533
534 //
535 // Do not create any child for END remaining device path.
536 //
537 if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) {
538 return EFI_SUCCESS;
539 }
540
541 if (Status == EFI_ALREADY_STARTED) {
542 if (RemainingDevicePath == NULL) {
543 //
544 // If RemainingDevicePath is NULL or is the End of Device Path Node
545 //
546 return EFI_SUCCESS;
547 }
548
549 //
550 // This driver can only produce one child per serial port.
551 // Change its terminal type as remaining device path requests.
552 //
553 Status = gBS->OpenProtocolInformation (
554 Controller,
555 &gEfiSerialIoProtocolGuid,
556 &OpenInfoBuffer,
557 &EntryCount
558 );
559 if (!EFI_ERROR (Status)) {
560 Status = EFI_NOT_FOUND;
561 for (Index = 0; Index < EntryCount; Index++) {
562 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
563 Status = gBS->OpenProtocol (
564 OpenInfoBuffer[Index].ControllerHandle,
565 &gEfiSimpleTextInProtocolGuid,
566 (VOID **)&SimpleTextInput,
567 This->DriverBindingHandle,
568 Controller,
569 EFI_OPEN_PROTOCOL_GET_PROTOCOL
570 );
571 if (!EFI_ERROR (Status)) {
572 TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (SimpleTextInput);
573 TerminalType = TerminalTypeFromGuid (&((VENDOR_DEVICE_PATH *)RemainingDevicePath)->Guid);
574 ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));
575 if (TerminalDevice->TerminalType != TerminalType) {
576 Status = InitializeControllerNameTable (TerminalType, &ControllerNameTable);
577 if (!EFI_ERROR (Status)) {
578 StopTerminalStateMachine (TerminalDevice);
579 //
580 // Update the device path
581 //
582 Vendor = TerminalDevice->DevicePath;
583 Status = gBS->LocateDevicePath (&gEfiSerialIoProtocolGuid, &Vendor, &SerialIoHandle);
584 ASSERT_EFI_ERROR (Status);
585 CopyGuid (&((VENDOR_DEVICE_PATH *)Vendor)->Guid, mTerminalType[TerminalType]);
586 Status = gBS->ReinstallProtocolInterface (
587 TerminalDevice->Handle,
588 &gEfiDevicePathProtocolGuid,
589 TerminalDevice->DevicePath,
590 TerminalDevice->DevicePath
591 );
592 if (!EFI_ERROR (Status)) {
593 TerminalDevice->TerminalType = TerminalType;
594 StartTerminalStateMachine (TerminalDevice);
595 FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
596 TerminalDevice->ControllerNameTable = ControllerNameTable;
597 } else {
598 //
599 // Restore the device path on failure
600 //
601 CopyGuid (&((VENDOR_DEVICE_PATH *)Vendor)->Guid, mTerminalType[TerminalDevice->TerminalType]);
602 FreeUnicodeStringTable (ControllerNameTable);
603 }
604 }
605 }
606 }
607
608 break;
609 }
610 }
611
612 FreePool (OpenInfoBuffer);
613 }
614
615 return Status;
616 }
617
618 //
619 // Initialize the Terminal Dev
620 //
621 TerminalDevice = AllocateCopyPool (sizeof (TERMINAL_DEV), &mTerminalDevTemplate);
622 if (TerminalDevice == NULL) {
623 Status = EFI_OUT_OF_RESOURCES;
624 goto CloseProtocols;
625 }
626
627 if (RemainingDevicePath == NULL) {
628 //
629 // If RemainingDevicePath is NULL, use default terminal type
630 //
631 TerminalDevice->TerminalType = PcdGet8 (PcdDefaultTerminalType);
632 } else {
633 //
634 // End of Device Path Node is handled in above.
635 //
636 ASSERT (!IsDevicePathEnd (RemainingDevicePath));
637 //
638 // If RemainingDevicePath isn't the End of Device Path Node,
639 // Use the RemainingDevicePath to determine the terminal type
640 //
641 TerminalDevice->TerminalType = TerminalTypeFromGuid (&((VENDOR_DEVICE_PATH *)RemainingDevicePath)->Guid);
642 }
643
644 ASSERT (TerminalDevice->TerminalType < ARRAY_SIZE (mTerminalType));
645 TerminalDevice->SerialIo = SerialIo;
646
647 //
648 // Build the component name for the child device
649 //
650 Status = InitializeControllerNameTable (TerminalDevice->TerminalType, &TerminalDevice->ControllerNameTable);
651 if (EFI_ERROR (Status)) {
652 goto FreeResources;
653 }
654
655 //
656 // Build the device path for the child device
657 //
658 Status = SetTerminalDevicePath (TerminalDevice->TerminalType, ParentDevicePath, &TerminalDevice->DevicePath);
659 if (EFI_ERROR (Status)) {
660 goto FreeResources;
661 }
662
663 InitializeListHead (&TerminalDevice->NotifyList);
664 Status = gBS->CreateEvent (
665 EVT_NOTIFY_WAIT,
666 TPL_NOTIFY,
667 TerminalConInWaitForKeyEx,
668 TerminalDevice,
669 &TerminalDevice->SimpleInputEx.WaitForKeyEx
670 );
671 ASSERT_EFI_ERROR (Status);
672
673 Status = gBS->CreateEvent (
674 EVT_NOTIFY_WAIT,
675 TPL_NOTIFY,
676 TerminalConInWaitForKey,
677 TerminalDevice,
678 &TerminalDevice->SimpleInput.WaitForKey
679 );
680 ASSERT_EFI_ERROR (Status);
681 Status = gBS->CreateEvent (
682 EVT_NOTIFY_SIGNAL,
683 TPL_CALLBACK,
684 KeyNotifyProcessHandler,
685 TerminalDevice,
686 &TerminalDevice->KeyNotifyProcessEvent
687 );
688 ASSERT_EFI_ERROR (Status);
689
690 //
691 // Allocates and initializes the FIFO buffer to be zero, used for accommodating
692 // the pre-read pending characters.
693 //
694 TerminalDevice->RawFiFo = AllocateZeroPool (sizeof (RAW_DATA_FIFO));
695 if (TerminalDevice->RawFiFo == NULL) {
696 goto FreeResources;
697 }
698
699 TerminalDevice->UnicodeFiFo = AllocateZeroPool (sizeof (UNICODE_FIFO));
700 if (TerminalDevice->UnicodeFiFo == NULL) {
701 goto FreeResources;
702 }
703
704 TerminalDevice->EfiKeyFiFo = AllocateZeroPool (sizeof (EFI_KEY_FIFO));
705 if (TerminalDevice->EfiKeyFiFo == NULL) {
706 goto FreeResources;
707 }
708
709 TerminalDevice->EfiKeyFiFoForNotify = AllocateZeroPool (sizeof (EFI_KEY_FIFO));
710 if (TerminalDevice->EfiKeyFiFoForNotify == NULL) {
711 goto FreeResources;
712 }
713
714 //
715 // Set the timeout value of serial buffer for keystroke response performance issue
716 //
717 Mode = TerminalDevice->SerialIo->Mode;
718
719 SerialInTimeOut = 0;
720 if (Mode->BaudRate != 0) {
721 SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN)Mode->BaudRate;
722 }
723
724 Status = TerminalDevice->SerialIo->SetAttributes (
725 TerminalDevice->SerialIo,
726 Mode->BaudRate,
727 Mode->ReceiveFifoDepth,
728 (UINT32)SerialInTimeOut,
729 (EFI_PARITY_TYPE)(Mode->Parity),
730 (UINT8)Mode->DataBits,
731 (EFI_STOP_BITS_TYPE)(Mode->StopBits)
732 );
733 if (EFI_ERROR (Status)) {
734 //
735 // if set attributes operation fails, invalidate
736 // the value of SerialInTimeOut,thus make it
737 // inconsistent with the default timeout value
738 // of serial buffer. This will invoke the recalculation
739 // in the readkeystroke routine.
740 //
741 TerminalDevice->SerialInTimeOut = 0;
742 } else {
743 TerminalDevice->SerialInTimeOut = SerialInTimeOut;
744 }
745
746 SimpleTextOutput = &TerminalDevice->SimpleTextOutput;
747 SimpleTextInput = &TerminalDevice->SimpleInput;
748
749 //
750 // Initialize SimpleTextOut instance
751 //
752 SimpleTextOutput->Mode = &TerminalDevice->SimpleTextOutputMode;
753 TerminalDevice->TerminalConsoleModeData = InitializeTerminalConsoleTextMode (
754 &SimpleTextOutput->Mode->MaxMode
755 );
756 if (TerminalDevice->TerminalConsoleModeData == NULL) {
757 goto FreeResources;
758 }
759
760 //
761 // For terminal devices, cursor is always visible
762 //
763 SimpleTextOutput->Mode->CursorVisible = TRUE;
764 Status = SimpleTextOutput->SetAttribute (SimpleTextOutput, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
765 if (!EFI_ERROR (Status)) {
766 Status = SimpleTextOutput->Reset (SimpleTextOutput, FALSE);
767 }
768
769 if (EFI_ERROR (Status)) {
770 goto ReportError;
771 }
772
773 //
774 // Initialize SimpleTextInput instance
775 //
776 Status = SimpleTextInput->Reset (SimpleTextInput, FALSE);
777 if (EFI_ERROR (Status)) {
778 goto ReportError;
779 }
780
781 Status = gBS->InstallMultipleProtocolInterfaces (
782 &TerminalDevice->Handle,
783 &gEfiSimpleTextInProtocolGuid,
784 &TerminalDevice->SimpleInput,
785 &gEfiSimpleTextInputExProtocolGuid,
786 &TerminalDevice->SimpleInputEx,
787 &gEfiSimpleTextOutProtocolGuid,
788 &TerminalDevice->SimpleTextOutput,
789 &gEfiDevicePathProtocolGuid,
790 TerminalDevice->DevicePath,
791 NULL
792 );
793 if (!EFI_ERROR (Status)) {
794 Status = gBS->OpenProtocol (
795 Controller,
796 &gEfiSerialIoProtocolGuid,
797 (VOID **)&TerminalDevice->SerialIo,
798 This->DriverBindingHandle,
799 TerminalDevice->Handle,
800 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
801 );
802 ASSERT_EFI_ERROR (Status);
803 StartTerminalStateMachine (TerminalDevice);
804 return Status;
805 }
806
807 ReportError:
808 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
809 EFI_ERROR_CODE | EFI_ERROR_MINOR,
810 (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),
811 ParentDevicePath
812 );
813
814 FreeResources:
815 ASSERT (TerminalDevice != NULL);
816
817 if (TerminalDevice->SimpleInput.WaitForKey != NULL) {
818 gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);
819 }
820
821 if (TerminalDevice->SimpleInputEx.WaitForKeyEx != NULL) {
822 gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);
823 }
824
825 if (TerminalDevice->KeyNotifyProcessEvent != NULL) {
826 gBS->CloseEvent (TerminalDevice->KeyNotifyProcessEvent);
827 }
828
829 if (TerminalDevice->RawFiFo != NULL) {
830 FreePool (TerminalDevice->RawFiFo);
831 }
832
833 if (TerminalDevice->UnicodeFiFo != NULL) {
834 FreePool (TerminalDevice->UnicodeFiFo);
835 }
836
837 if (TerminalDevice->EfiKeyFiFo != NULL) {
838 FreePool (TerminalDevice->EfiKeyFiFo);
839 }
840
841 if (TerminalDevice->EfiKeyFiFoForNotify != NULL) {
842 FreePool (TerminalDevice->EfiKeyFiFoForNotify);
843 }
844
845 if (TerminalDevice->ControllerNameTable != NULL) {
846 FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
847 }
848
849 if (TerminalDevice->DevicePath != NULL) {
850 FreePool (TerminalDevice->DevicePath);
851 }
852
853 if (TerminalDevice->TerminalConsoleModeData != NULL) {
854 FreePool (TerminalDevice->TerminalConsoleModeData);
855 }
856
857 FreePool (TerminalDevice);
858
859 CloseProtocols:
860
861 //
862 // Remove Parent Device Path from
863 // the Console Device Environment Variables
864 //
865 TerminalRemoveConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME, ParentDevicePath);
866 TerminalRemoveConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
867 TerminalRemoveConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
868
869 Status = gBS->CloseProtocol (
870 Controller,
871 &gEfiSerialIoProtocolGuid,
872 This->DriverBindingHandle,
873 Controller
874 );
875 ASSERT_EFI_ERROR (Status);
876
877 Status = gBS->CloseProtocol (
878 Controller,
879 &gEfiDevicePathProtocolGuid,
880 This->DriverBindingHandle,
881 Controller
882 );
883 ASSERT_EFI_ERROR (Status);
884 return Status;
885 }
886
887 /**
888 Stop this driver on Controller by closing Simple Text In, Simple Text
889 In Ex, Simple Text Out protocol, and removing parent device path from
890 Console Device Environment Variables.
891
892 @param This Protocol instance pointer.
893 @param Controller Handle of device to stop driver on
894 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
895 children is zero stop the entire bus driver.
896 @param ChildHandleBuffer List of Child Handles to Stop.
897
898 @retval EFI_SUCCESS This driver is removed Controller.
899 @retval other This driver could not be removed from this device.
900
901 **/
902 EFI_STATUS
903 EFIAPI
904 TerminalDriverBindingStop (
905 IN EFI_DRIVER_BINDING_PROTOCOL *This,
906 IN EFI_HANDLE Controller,
907 IN UINTN NumberOfChildren,
908 IN EFI_HANDLE *ChildHandleBuffer
909 )
910 {
911 EFI_STATUS Status;
912 UINTN Index;
913 BOOLEAN AllChildrenStopped;
914 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;
915 TERMINAL_DEV *TerminalDevice;
916 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
917 EFI_SERIAL_IO_PROTOCOL *SerialIo;
918
919 //
920 // Complete all outstanding transactions to Controller.
921 // Don't allow any new transaction to Controller to be started.
922 //
923 if (NumberOfChildren == 0) {
924 //
925 // Close the bus driver
926 //
927 Status = gBS->OpenProtocol (
928 Controller,
929 &gEfiDevicePathProtocolGuid,
930 (VOID **)&ParentDevicePath,
931 This->DriverBindingHandle,
932 Controller,
933 EFI_OPEN_PROTOCOL_GET_PROTOCOL
934 );
935 ASSERT_EFI_ERROR (Status);
936
937 //
938 // Remove Parent Device Path from
939 // the Console Device Environment Variables
940 //
941 TerminalRemoveConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME, ParentDevicePath);
942 TerminalRemoveConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
943 TerminalRemoveConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
944
945 gBS->CloseProtocol (
946 Controller,
947 &gEfiSerialIoProtocolGuid,
948 This->DriverBindingHandle,
949 Controller
950 );
951
952 gBS->CloseProtocol (
953 Controller,
954 &gEfiDevicePathProtocolGuid,
955 This->DriverBindingHandle,
956 Controller
957 );
958
959 return EFI_SUCCESS;
960 }
961
962 AllChildrenStopped = TRUE;
963
964 for (Index = 0; Index < NumberOfChildren; Index++) {
965 Status = gBS->OpenProtocol (
966 ChildHandleBuffer[Index],
967 &gEfiSimpleTextOutProtocolGuid,
968 (VOID **)&SimpleTextOutput,
969 This->DriverBindingHandle,
970 ChildHandleBuffer[Index],
971 EFI_OPEN_PROTOCOL_GET_PROTOCOL
972 );
973 if (!EFI_ERROR (Status)) {
974 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);
975
976 gBS->CloseProtocol (
977 Controller,
978 &gEfiSerialIoProtocolGuid,
979 This->DriverBindingHandle,
980 ChildHandleBuffer[Index]
981 );
982
983 Status = gBS->UninstallMultipleProtocolInterfaces (
984 ChildHandleBuffer[Index],
985 &gEfiSimpleTextInProtocolGuid,
986 &TerminalDevice->SimpleInput,
987 &gEfiSimpleTextInputExProtocolGuid,
988 &TerminalDevice->SimpleInputEx,
989 &gEfiSimpleTextOutProtocolGuid,
990 &TerminalDevice->SimpleTextOutput,
991 &gEfiDevicePathProtocolGuid,
992 TerminalDevice->DevicePath,
993 NULL
994 );
995 if (EFI_ERROR (Status)) {
996 gBS->OpenProtocol (
997 Controller,
998 &gEfiSerialIoProtocolGuid,
999 (VOID **)&SerialIo,
1000 This->DriverBindingHandle,
1001 ChildHandleBuffer[Index],
1002 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1003 );
1004 } else {
1005 FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
1006 StopTerminalStateMachine (TerminalDevice);
1007 gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);
1008 gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);
1009 gBS->CloseEvent (TerminalDevice->KeyNotifyProcessEvent);
1010 TerminalFreeNotifyList (&TerminalDevice->NotifyList);
1011 FreePool (TerminalDevice->DevicePath);
1012 FreePool (TerminalDevice->TerminalConsoleModeData);
1013 FreePool (TerminalDevice);
1014 }
1015 }
1016
1017 if (EFI_ERROR (Status)) {
1018 AllChildrenStopped = FALSE;
1019 }
1020 }
1021
1022 if (!AllChildrenStopped) {
1023 return EFI_DEVICE_ERROR;
1024 }
1025
1026 return EFI_SUCCESS;
1027 }
1028
1029 /**
1030 Compare a device path data structure to that of all the nodes of a
1031 second device path instance.
1032
1033 @param Multi A pointer to a multi-instance device path data structure.
1034 @param Single A pointer to a single-instance device path data structure.
1035
1036 @retval TRUE If the Single is contained within Multi.
1037 @retval FALSE The Single is not match within Multi.
1038
1039 **/
1040 BOOLEAN
1041 MatchDevicePaths (
1042 IN EFI_DEVICE_PATH_PROTOCOL *Multi,
1043 IN EFI_DEVICE_PATH_PROTOCOL *Single
1044 )
1045 {
1046 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1047 EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
1048 UINTN Size;
1049
1050 DevicePath = Multi;
1051 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
1052 //
1053 // Search for the match of 'Single' in 'Multi'
1054 //
1055 while (DevicePathInst != NULL) {
1056 //
1057 // If the single device path is found in multiple device paths,
1058 // return success
1059 //
1060 if (CompareMem (Single, DevicePathInst, Size) == 0) {
1061 FreePool (DevicePathInst);
1062 return TRUE;
1063 }
1064
1065 FreePool (DevicePathInst);
1066 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
1067 }
1068
1069 return FALSE;
1070 }
1071
1072 /**
1073 Update terminal device path in Console Device Environment Variables.
1074
1075 @param VariableName The Console Device Environment Variable.
1076 @param ParentDevicePath The terminal device path to be updated.
1077
1078 **/
1079 VOID
1080 TerminalUpdateConsoleDevVariable (
1081 IN CHAR16 *VariableName,
1082 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
1083 )
1084 {
1085 EFI_STATUS Status;
1086 UINTN NameSize;
1087 UINTN VariableSize;
1088 TERMINAL_TYPE TerminalType;
1089 EFI_DEVICE_PATH_PROTOCOL *Variable;
1090 EFI_DEVICE_PATH_PROTOCOL *NewVariable;
1091 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1092 EDKII_SET_VARIABLE_STATUS *SetVariableStatus;
1093
1094 //
1095 // Get global variable and its size according to the name given.
1096 //
1097 Status = GetEfiGlobalVariable2 (VariableName, (VOID **)&Variable, NULL);
1098 if (Status == EFI_NOT_FOUND) {
1099 Status = EFI_SUCCESS;
1100 Variable = NULL;
1101 }
1102
1103 if (EFI_ERROR (Status)) {
1104 return;
1105 }
1106
1107 //
1108 // Append terminal device path onto the variable.
1109 //
1110 for (TerminalType = 0; TerminalType < ARRAY_SIZE (mTerminalType); TerminalType++) {
1111 SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);
1112
1113 if (TempDevicePath != NULL) {
1114 if (!MatchDevicePaths (Variable, TempDevicePath)) {
1115 NewVariable = AppendDevicePathInstance (Variable, TempDevicePath);
1116 if (NewVariable != NULL) {
1117 if (Variable != NULL) {
1118 FreePool (Variable);
1119 }
1120
1121 Variable = NewVariable;
1122 }
1123 }
1124
1125 FreePool (TempDevicePath);
1126 }
1127 }
1128
1129 VariableSize = GetDevicePathSize (Variable);
1130
1131 Status = gRT->SetVariable (
1132 VariableName,
1133 &gEfiGlobalVariableGuid,
1134 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
1135 VariableSize,
1136 Variable
1137 );
1138
1139 if (EFI_ERROR (Status)) {
1140 NameSize = StrSize (VariableName);
1141 SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + VariableSize);
1142 if (SetVariableStatus != NULL) {
1143 CopyGuid (&SetVariableStatus->Guid, &gEfiGlobalVariableGuid);
1144 SetVariableStatus->NameSize = NameSize;
1145 SetVariableStatus->DataSize = VariableSize;
1146 SetVariableStatus->SetStatus = Status;
1147 SetVariableStatus->Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
1148 CopyMem (SetVariableStatus + 1, VariableName, NameSize);
1149 CopyMem (((UINT8 *)(SetVariableStatus + 1)) + NameSize, Variable, VariableSize);
1150
1151 REPORT_STATUS_CODE_EX (
1152 EFI_ERROR_CODE,
1153 PcdGet32 (PcdErrorCodeSetVariable),
1154 0,
1155 NULL,
1156 &gEdkiiStatusCodeDataTypeVariableGuid,
1157 SetVariableStatus,
1158 sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + VariableSize
1159 );
1160
1161 FreePool (SetVariableStatus);
1162 }
1163 }
1164
1165 FreePool (Variable);
1166
1167 return;
1168 }
1169
1170 /**
1171 Remove terminal device path from Console Device Environment Variables.
1172
1173 @param VariableName Console Device Environment Variables.
1174 @param ParentDevicePath The terminal device path to be updated.
1175
1176 **/
1177 VOID
1178 TerminalRemoveConsoleDevVariable (
1179 IN CHAR16 *VariableName,
1180 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
1181 )
1182 {
1183 EFI_STATUS Status;
1184 BOOLEAN FoundOne;
1185 BOOLEAN Match;
1186 UINTN VariableSize;
1187 UINTN InstanceSize;
1188 TERMINAL_TYPE TerminalType;
1189 EFI_DEVICE_PATH_PROTOCOL *Instance;
1190 EFI_DEVICE_PATH_PROTOCOL *Variable;
1191 EFI_DEVICE_PATH_PROTOCOL *OriginalVariable;
1192 EFI_DEVICE_PATH_PROTOCOL *NewVariable;
1193 EFI_DEVICE_PATH_PROTOCOL *SavedNewVariable;
1194 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1195
1196 Instance = NULL;
1197
1198 //
1199 // Get global variable and its size according to the name given.
1200 //
1201 GetEfiGlobalVariable2 (VariableName, (VOID **)&Variable, NULL);
1202 if (Variable == NULL) {
1203 return;
1204 }
1205
1206 FoundOne = FALSE;
1207 OriginalVariable = Variable;
1208 NewVariable = NULL;
1209
1210 //
1211 // Get first device path instance from Variable
1212 //
1213 Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);
1214 if (Instance == NULL) {
1215 FreePool (OriginalVariable);
1216 return;
1217 }
1218
1219 //
1220 // Loop through all the device path instances of Variable
1221 //
1222 do {
1223 //
1224 // Loop through all the terminal types that this driver supports
1225 //
1226 Match = FALSE;
1227 for (TerminalType = 0; TerminalType < ARRAY_SIZE (mTerminalType); TerminalType++) {
1228 SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);
1229
1230 //
1231 // Compare the generated device path to the current device path instance
1232 //
1233 if (TempDevicePath != NULL) {
1234 if (CompareMem (Instance, TempDevicePath, InstanceSize) == 0) {
1235 Match = TRUE;
1236 FoundOne = TRUE;
1237 }
1238
1239 FreePool (TempDevicePath);
1240 }
1241 }
1242
1243 //
1244 // If a match was not found, then keep the current device path instance
1245 //
1246 if (!Match) {
1247 SavedNewVariable = NewVariable;
1248 NewVariable = AppendDevicePathInstance (NewVariable, Instance);
1249 if (SavedNewVariable != NULL) {
1250 FreePool (SavedNewVariable);
1251 }
1252 }
1253
1254 //
1255 // Get next device path instance from Variable
1256 //
1257 FreePool (Instance);
1258 Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);
1259 } while (Instance != NULL);
1260
1261 FreePool (OriginalVariable);
1262
1263 if (FoundOne) {
1264 VariableSize = GetDevicePathSize (NewVariable);
1265
1266 Status = gRT->SetVariable (
1267 VariableName,
1268 &gEfiGlobalVariableGuid,
1269 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
1270 VariableSize,
1271 NewVariable
1272 );
1273 //
1274 // Shrinking variable with existing variable driver implementation shouldn't fail.
1275 //
1276 ASSERT_EFI_ERROR (Status);
1277 }
1278
1279 if (NewVariable != NULL) {
1280 FreePool (NewVariable);
1281 }
1282
1283 return;
1284 }
1285
1286 /**
1287 Build terminal device path according to terminal type.
1288
1289 @param TerminalType The terminal type is PC ANSI, VT100, VT100+ or VT-UTF8.
1290 @param ParentDevicePath Parent device path.
1291 @param TerminalDevicePath Returned terminal device path, if building successfully.
1292
1293 @retval EFI_UNSUPPORTED Terminal does not belong to the supported type.
1294 @retval EFI_OUT_OF_RESOURCES Generate terminal device path failed.
1295 @retval EFI_SUCCESS Build terminal device path successfully.
1296
1297 **/
1298 EFI_STATUS
1299 SetTerminalDevicePath (
1300 IN TERMINAL_TYPE TerminalType,
1301 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
1302 OUT EFI_DEVICE_PATH_PROTOCOL **TerminalDevicePath
1303 )
1304 {
1305 VENDOR_DEVICE_PATH Node;
1306
1307 ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));
1308 Node.Header.Type = MESSAGING_DEVICE_PATH;
1309 Node.Header.SubType = MSG_VENDOR_DP;
1310 SetDevicePathNodeLength (&Node.Header, sizeof (VENDOR_DEVICE_PATH));
1311 CopyGuid (&Node.Guid, mTerminalType[TerminalType]);
1312
1313 //
1314 // Append the terminal node onto parent device path
1315 // to generate a complete terminal device path.
1316 //
1317 *TerminalDevicePath = AppendDevicePathNode (
1318 ParentDevicePath,
1319 (EFI_DEVICE_PATH_PROTOCOL *)&Node
1320 );
1321 if (*TerminalDevicePath == NULL) {
1322 return EFI_OUT_OF_RESOURCES;
1323 }
1324
1325 return EFI_SUCCESS;
1326 }
1327
1328 /**
1329 The user Entry Point for module Terminal. The user code starts with this function.
1330
1331 @param ImageHandle The firmware allocated handle for the EFI image.
1332 @param SystemTable A pointer to the EFI System Table.
1333
1334 @retval EFI_SUCCESS The entry point is executed successfully.
1335 @retval other Some error occurs when executing this entry point.
1336
1337 **/
1338 EFI_STATUS
1339 EFIAPI
1340 InitializeTerminal (
1341 IN EFI_HANDLE ImageHandle,
1342 IN EFI_SYSTEM_TABLE *SystemTable
1343 )
1344 {
1345 EFI_STATUS Status;
1346
1347 //
1348 // Install driver model protocol(s).
1349 //
1350 Status = EfiLibInstallDriverBindingComponentName2 (
1351 ImageHandle,
1352 SystemTable,
1353 &gTerminalDriverBinding,
1354 ImageHandle,
1355 &gTerminalComponentName,
1356 &gTerminalComponentName2
1357 );
1358 ASSERT_EFI_ERROR (Status);
1359
1360 return Status;
1361 }
1362
1363 /**
1364 Check if the device supports hot-plug through its device path.
1365
1366 This function could be updated to check more types of Hot Plug devices.
1367 Currently, it checks USB and PCCard device.
1368
1369 @param DevicePath Pointer to device's device path.
1370
1371 @retval TRUE The devcie is a hot-plug device
1372 @retval FALSE The devcie is not a hot-plug device.
1373
1374 **/
1375 BOOLEAN
1376 IsHotPlugDevice (
1377 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
1378 )
1379 {
1380 EFI_DEVICE_PATH_PROTOCOL *CheckDevicePath;
1381
1382 CheckDevicePath = DevicePath;
1383 while (!IsDevicePathEnd (CheckDevicePath)) {
1384 //
1385 // Check device whether is hot plug device or not throught Device Path
1386 //
1387 if ((DevicePathType (CheckDevicePath) == MESSAGING_DEVICE_PATH) &&
1388 ((DevicePathSubType (CheckDevicePath) == MSG_USB_DP) ||
1389 (DevicePathSubType (CheckDevicePath) == MSG_USB_CLASS_DP) ||
1390 (DevicePathSubType (CheckDevicePath) == MSG_USB_WWID_DP)))
1391 {
1392 //
1393 // If Device is USB device
1394 //
1395 return TRUE;
1396 }
1397
1398 if ((DevicePathType (CheckDevicePath) == HARDWARE_DEVICE_PATH) &&
1399 (DevicePathSubType (CheckDevicePath) == HW_PCCARD_DP))
1400 {
1401 //
1402 // If Device is PCCard
1403 //
1404 return TRUE;
1405 }
1406
1407 CheckDevicePath = NextDevicePathNode (CheckDevicePath);
1408 }
1409
1410 return FALSE;
1411 }