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