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