]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
Fix the terminal driver to call hotkey callback even no one is calling ReadKeyStroke
[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 - 2011, 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 *gTerminalType[] = {
33 &gEfiPcAnsiGuid,
34 &gEfiVT100Guid,
35 &gEfiVT100PlusGuid,
36 &gEfiVTUTF8Guid
37 };
38
39
40 TERMINAL_DEV mTerminalDevTemplate = {
41 TERMINAL_DEV_SIGNATURE,
42 NULL,
43 0,
44 NULL,
45 NULL,
46 { // SimpleTextInput
47 TerminalConInReset,
48 TerminalConInReadKeyStroke,
49 NULL
50 },
51 { // SimpleTextOutput
52 TerminalConOutReset,
53 TerminalConOutOutputString,
54 TerminalConOutTestString,
55 TerminalConOutQueryMode,
56 TerminalConOutSetMode,
57 TerminalConOutSetAttribute,
58 TerminalConOutClearScreen,
59 TerminalConOutSetCursorPosition,
60 TerminalConOutEnableCursor,
61 NULL
62 },
63 { // SimpleTextOutputMode
64 1, // MaxMode
65 0, // Mode
66 EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK), // Attribute
67 0, // CursorColumn
68 0, // CursorRow
69 TRUE // CursorVisible
70 },
71 0, // SerialInTimeOut
72
73 NULL, // RawFifo
74 NULL, // UnicodeFiFo
75 NULL, // EfiKeyFiFo
76
77 NULL, // ControllerNameTable
78 NULL, // TimerEvent
79 NULL, // TwoSecondTimeOut
80 INPUT_STATE_DEFAULT,
81 RESET_STATE_DEFAULT,
82 FALSE,
83 { // SimpleTextInputEx
84 TerminalConInResetEx,
85 TerminalConInReadKeyStrokeEx,
86 NULL,
87 TerminalConInSetState,
88 TerminalConInRegisterKeyNotify,
89 TerminalConInUnregisterKeyNotify,
90 },
91 { // NotifyList
92 NULL,
93 NULL,
94 }
95 };
96
97 /**
98 Test to see if this driver supports Controller.
99
100 @param This Protocol instance pointer.
101 @param Controller Handle of device to test
102 @param RemainingDevicePath Optional parameter use to pick a specific child
103 device to start.
104
105 @retval EFI_SUCCESS This driver supports this device.
106 @retval EFI_ALREADY_STARTED This driver is already running on this device.
107 @retval other This driver does not support this device.
108
109 **/
110 EFI_STATUS
111 EFIAPI
112 TerminalDriverBindingSupported (
113 IN EFI_DRIVER_BINDING_PROTOCOL *This,
114 IN EFI_HANDLE Controller,
115 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
116 )
117 {
118 EFI_STATUS Status;
119 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
120 EFI_SERIAL_IO_PROTOCOL *SerialIo;
121 VENDOR_DEVICE_PATH *Node;
122
123 //
124 // If remaining device path is not NULL, then make sure it is a
125 // device path that describes a terminal communications protocol.
126 //
127 if (RemainingDevicePath != NULL) {
128 //
129 // Check if RemainingDevicePath is the End of Device Path Node,
130 // if yes, go on checking other conditions
131 //
132 if (!IsDevicePathEnd (RemainingDevicePath)) {
133 //
134 // If RemainingDevicePath isn't the End of Device Path Node,
135 // check its validation
136 //
137 Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;
138
139 if (Node->Header.Type != MESSAGING_DEVICE_PATH ||
140 Node->Header.SubType != MSG_VENDOR_DP ||
141 DevicePathNodeLength(&Node->Header) != sizeof(VENDOR_DEVICE_PATH)) {
142
143 return EFI_UNSUPPORTED;
144
145 }
146 //
147 // only supports PC ANSI, VT100, VT100+ and VT-UTF8 terminal types
148 //
149 if (!CompareGuid (&Node->Guid, &gEfiPcAnsiGuid) &&
150 !CompareGuid (&Node->Guid, &gEfiVT100Guid) &&
151 !CompareGuid (&Node->Guid, &gEfiVT100PlusGuid) &&
152 !CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {
153
154 return EFI_UNSUPPORTED;
155 }
156 }
157 }
158 //
159 // Open the IO Abstraction(s) needed to perform the supported test
160 // The Controller must support the Serial I/O Protocol.
161 // This driver is a bus driver with at most 1 child device, so it is
162 // ok for it to be already started.
163 //
164 Status = gBS->OpenProtocol (
165 Controller,
166 &gEfiSerialIoProtocolGuid,
167 (VOID **) &SerialIo,
168 This->DriverBindingHandle,
169 Controller,
170 EFI_OPEN_PROTOCOL_BY_DRIVER
171 );
172 if (Status == EFI_ALREADY_STARTED) {
173 return EFI_SUCCESS;
174 }
175
176 if (EFI_ERROR (Status)) {
177 return Status;
178 }
179
180 //
181 // Close the I/O Abstraction(s) used to perform the supported test
182 //
183 gBS->CloseProtocol (
184 Controller,
185 &gEfiSerialIoProtocolGuid,
186 This->DriverBindingHandle,
187 Controller
188 );
189
190 //
191 // Open the EFI Device Path protocol needed to perform the supported test
192 //
193 Status = gBS->OpenProtocol (
194 Controller,
195 &gEfiDevicePathProtocolGuid,
196 (VOID **) &ParentDevicePath,
197 This->DriverBindingHandle,
198 Controller,
199 EFI_OPEN_PROTOCOL_BY_DRIVER
200 );
201 if (Status == EFI_ALREADY_STARTED) {
202 return EFI_SUCCESS;
203 }
204
205 if (EFI_ERROR (Status)) {
206 return Status;
207 }
208
209 //
210 // Close protocol, don't use device path protocol in the Support() function
211 //
212 gBS->CloseProtocol (
213 Controller,
214 &gEfiDevicePathProtocolGuid,
215 This->DriverBindingHandle,
216 Controller
217 );
218
219 return Status;
220 }
221
222 /**
223 Build the terminal device path for the child device according to the
224 terminal type.
225
226 @param ParentDevicePath Parent device path.
227 @param RemainingDevicePath A specific child device.
228
229 @return The child device path built.
230
231 **/
232 EFI_DEVICE_PATH_PROTOCOL*
233 EFIAPI
234 BuildTerminalDevpath (
235 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
236 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
237 )
238 {
239 EFI_DEVICE_PATH_PROTOCOL *TerminalDevicePath;
240 UINT8 TerminalType;
241 VENDOR_DEVICE_PATH *Node;
242 EFI_STATUS Status;
243
244 TerminalDevicePath = NULL;
245 TerminalType = PCANSITYPE;
246
247 //
248 // Use the RemainingDevicePath to determine the terminal type
249 //
250 Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;
251 if (Node == NULL) {
252 TerminalType = PCANSITYPE;
253
254 } else if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) {
255
256 TerminalType = PCANSITYPE;
257
258 } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) {
259
260 TerminalType = VT100TYPE;
261
262 } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) {
263
264 TerminalType = VT100PLUSTYPE;
265
266 } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {
267
268 TerminalType = VTUTF8TYPE;
269
270 } else {
271 return NULL;
272 }
273
274 //
275 // Build the device path for the child device
276 //
277 Status = SetTerminalDevicePath (
278 TerminalType,
279 ParentDevicePath,
280 &TerminalDevicePath
281 );
282 if (EFI_ERROR (Status)) {
283 return NULL;
284 }
285 return TerminalDevicePath;
286 }
287
288 /**
289 Compare a device path data structure to that of all the nodes of a
290 second device path instance.
291
292 @param Multi A pointer to a multi-instance device path data structure.
293 @param Single A pointer to a single-instance device path data structure.
294
295 @retval TRUE If the Single is contained within Multi.
296 @retval FALSE The Single is not match within Multi.
297
298 **/
299 BOOLEAN
300 MatchDevicePaths (
301 IN EFI_DEVICE_PATH_PROTOCOL *Multi,
302 IN EFI_DEVICE_PATH_PROTOCOL *Single
303 )
304 {
305 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
306 EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
307 UINTN Size;
308
309 DevicePath = Multi;
310 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
311 //
312 // Search for the match of 'Single' in 'Multi'
313 //
314 while (DevicePathInst != NULL) {
315 //
316 // If the single device path is found in multiple device paths,
317 // return success
318 //
319 if (CompareMem (Single, DevicePathInst, Size) == 0) {
320 FreePool (DevicePathInst);
321 return TRUE;
322 }
323
324 FreePool (DevicePathInst);
325 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
326 }
327
328 return FALSE;
329 }
330
331 /**
332 Check whether the terminal device path is in the global variable.
333
334 @param VariableName Pointer to one global variable.
335 @param TerminalDevicePath Pointer to the terminal device's device path.
336
337 @retval TRUE The devcie is in the global variable.
338 @retval FALSE The devcie is not in the global variable.
339
340 **/
341 BOOLEAN
342 IsTerminalInConsoleVariable (
343 IN CHAR16 *VariableName,
344 IN EFI_DEVICE_PATH_PROTOCOL *TerminalDevicePath
345 )
346 {
347 EFI_DEVICE_PATH_PROTOCOL *Variable;
348 BOOLEAN ReturnFlag;
349
350 //
351 // Get global variable and its size according to the name given.
352 //
353 Variable = GetEfiGlobalVariable (VariableName);
354 if (Variable == NULL) {
355 return FALSE;
356 }
357
358 //
359 // Check whether the terminal device path is one of the variable instances.
360 //
361 ReturnFlag = MatchDevicePaths (Variable, TerminalDevicePath);
362
363 FreePool (Variable);
364
365 return ReturnFlag;
366 }
367
368 /**
369 Free notify functions list.
370
371 @param ListHead The list head
372
373 @retval EFI_SUCCESS Free the notify list successfully.
374 @retval EFI_INVALID_PARAMETER ListHead is NULL.
375
376 **/
377 EFI_STATUS
378 TerminalFreeNotifyList (
379 IN OUT LIST_ENTRY *ListHead
380 )
381 {
382 TERMINAL_CONSOLE_IN_EX_NOTIFY *NotifyNode;
383
384 if (ListHead == NULL) {
385 return EFI_INVALID_PARAMETER;
386 }
387 while (!IsListEmpty (ListHead)) {
388 NotifyNode = CR (
389 ListHead->ForwardLink,
390 TERMINAL_CONSOLE_IN_EX_NOTIFY,
391 NotifyEntry,
392 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
393 );
394 RemoveEntryList (ListHead->ForwardLink);
395 FreePool (NotifyNode);
396 }
397
398 return EFI_SUCCESS;
399 }
400
401
402 /**
403 Start this driver on Controller by opening a Serial IO protocol,
404 reading Device Path, and creating a child handle with a Simple Text In,
405 Simple Text In Ex and Simple Text Out protocol, and device path protocol.
406 And store Console Device Environment Variables.
407
408 @param This Protocol instance pointer.
409 @param Controller Handle of device to bind driver to
410 @param RemainingDevicePath Optional parameter use to pick a specific child
411 device to start.
412
413 @retval EFI_SUCCESS This driver is added to Controller.
414 @retval EFI_ALREADY_STARTED This driver is already running on Controller.
415 @retval other This driver does not support this device.
416
417 **/
418 EFI_STATUS
419 EFIAPI
420 TerminalDriverBindingStart (
421 IN EFI_DRIVER_BINDING_PROTOCOL *This,
422 IN EFI_HANDLE Controller,
423 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
424 )
425 {
426 EFI_STATUS Status;
427 EFI_SERIAL_IO_PROTOCOL *SerialIo;
428 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
429 VENDOR_DEVICE_PATH *Node;
430 VENDOR_DEVICE_PATH *DefaultNode;
431 EFI_SERIAL_IO_MODE *Mode;
432 UINTN SerialInTimeOut;
433 TERMINAL_DEV *TerminalDevice;
434 UINT8 TerminalType;
435 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
436 UINTN EntryCount;
437 UINTN Index;
438 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
439 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;
440 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextInput;
441 BOOLEAN ConInSelected;
442 BOOLEAN ConOutSelected;
443 BOOLEAN NullRemaining;
444 BOOLEAN SimTxtInInstalled;
445 BOOLEAN SimTxtOutInstalled;
446 BOOLEAN FirstEnter;
447
448 TerminalDevice = NULL;
449 DefaultNode = NULL;
450 ConInSelected = FALSE;
451 ConOutSelected = FALSE;
452 NullRemaining = TRUE;
453 SimTxtInInstalled = FALSE;
454 SimTxtOutInstalled = FALSE;
455 FirstEnter = FALSE;
456 //
457 // Get the Device Path Protocol to build the device path of the child device
458 //
459 Status = gBS->OpenProtocol (
460 Controller,
461 &gEfiDevicePathProtocolGuid,
462 (VOID **) &ParentDevicePath,
463 This->DriverBindingHandle,
464 Controller,
465 EFI_OPEN_PROTOCOL_BY_DRIVER
466 );
467 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
468 return Status;
469 }
470
471 //
472 // Open the Serial I/O Protocol BY_DRIVER. It might already be started.
473 //
474 Status = gBS->OpenProtocol (
475 Controller,
476 &gEfiSerialIoProtocolGuid,
477 (VOID **) &SerialIo,
478 This->DriverBindingHandle,
479 Controller,
480 EFI_OPEN_PROTOCOL_BY_DRIVER
481 );
482 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
483 return Status;
484 }
485
486 if (Status != EFI_ALREADY_STARTED) {
487 //
488 // the serial I/O protocol never be opened before, it is the first
489 // time to start the serial Io controller
490 //
491 FirstEnter = TRUE;
492 }
493
494 //
495 // Serial I/O is not already open by this driver, then tag the handle
496 // with the Terminal Driver GUID and update the ConInDev, ConOutDev, and
497 // StdErrDev variables with the list of possible terminal types on this
498 // serial port.
499 //
500 Status = gBS->OpenProtocol (
501 Controller,
502 &gEfiCallerIdGuid,
503 NULL,
504 This->DriverBindingHandle,
505 Controller,
506 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
507 );
508 if (EFI_ERROR (Status)) {
509 Status = gBS->InstallMultipleProtocolInterfaces (
510 &Controller,
511 &gEfiCallerIdGuid,
512 DuplicateDevicePath (ParentDevicePath),
513 NULL
514 );
515 if (EFI_ERROR (Status)) {
516 goto Error;
517 }
518
519 if (!IsHotPlugDevice (ParentDevicePath)) {
520 //
521 // if the serial device is a hot plug device, do not update the
522 // ConInDev, ConOutDev, and StdErrDev variables.
523 //
524 TerminalUpdateConsoleDevVariable (L"ConInDev", ParentDevicePath);
525 TerminalUpdateConsoleDevVariable (L"ConOutDev", ParentDevicePath);
526 TerminalUpdateConsoleDevVariable (L"ErrOutDev", ParentDevicePath);
527 }
528 }
529
530 //
531 // Check the requirement for the SimpleTxtIn and SimpleTxtOut protocols
532 //
533 // Simple In/Out Protocol will not be installed onto the handle if the
534 // device path to the handle is not present in the ConIn/ConOut
535 // environment variable. But If RemainingDevicePath is NULL, then always
536 // produce both Simple In and Simple Text Output Protocols. This is required
537 // for the connect all sequences to make sure all possible consoles are
538 // produced no matter what the current values of ConIn, ConOut, or StdErr are.
539 //
540 if (RemainingDevicePath == NULL) {
541 NullRemaining = TRUE;
542 }
543
544 DevicePath = BuildTerminalDevpath (ParentDevicePath, RemainingDevicePath);
545 if (DevicePath != NULL) {
546 ConInSelected = IsTerminalInConsoleVariable (L"ConIn", DevicePath);
547 ConOutSelected = IsTerminalInConsoleVariable (L"ConOut", DevicePath);
548 FreePool (DevicePath);
549 } else {
550 goto Error;
551 }
552 //
553 // Not create the child terminal handle if both Simple In/In Ex and
554 // Simple text Out protocols are not required to be published
555 //
556 if ((!ConInSelected)&&(!ConOutSelected)&&(!NullRemaining)) {
557 goto Error;
558 }
559
560 //
561 // create the child terminal handle during first entry
562 //
563 if (FirstEnter) {
564 //
565 // First enther the start funciton
566 //
567 FirstEnter = FALSE;
568 //
569 // Make sure a child handle does not already exist. This driver can only
570 // produce one child per serial port.
571 //
572 Status = gBS->OpenProtocolInformation (
573 Controller,
574 &gEfiSerialIoProtocolGuid,
575 &OpenInfoBuffer,
576 &EntryCount
577 );
578 if (!EFI_ERROR (Status)) {
579 Status = EFI_SUCCESS;
580 for (Index = 0; Index < EntryCount; Index++) {
581 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
582 Status = EFI_ALREADY_STARTED;
583 }
584 }
585
586 FreePool (OpenInfoBuffer);
587 if (EFI_ERROR (Status)) {
588 goto Error;
589 }
590 }
591
592 //
593 // If RemainingDevicePath is NULL, then create default device path node
594 //
595 if (RemainingDevicePath == NULL) {
596 DefaultNode = AllocateZeroPool (sizeof (VENDOR_DEVICE_PATH));
597 if (DefaultNode == NULL) {
598 Status = EFI_OUT_OF_RESOURCES;
599 goto Error;
600 }
601
602 TerminalType = PcdGet8 (PcdDefaultTerminalType);
603 //
604 // Must be between PCANSITYPE (0) and VTUTF8TYPE (3)
605 //
606 ASSERT (TerminalType <= VTUTF8TYPE);
607
608 CopyMem (&DefaultNode->Guid, gTerminalType[TerminalType], sizeof (EFI_GUID));
609 RemainingDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) DefaultNode;
610 } else if (!IsDevicePathEnd (RemainingDevicePath)) {
611 //
612 // If RemainingDevicePath isn't the End of Device Path Node,
613 // Use the RemainingDevicePath to determine the terminal type
614 //
615 Node = (VENDOR_DEVICE_PATH *)RemainingDevicePath;
616 if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) {
617 TerminalType = PCANSITYPE;
618 } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) {
619 TerminalType = VT100TYPE;
620 } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) {
621 TerminalType = VT100PLUSTYPE;
622 } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {
623 TerminalType = VTUTF8TYPE;
624 } else {
625 goto Error;
626 }
627 } else {
628 //
629 // If RemainingDevicePath is the End of Device Path Node,
630 // skip enumerate any device and return EFI_SUCESSS
631 //
632 return EFI_SUCCESS;
633 }
634
635 //
636 // Initialize the Terminal Dev
637 //
638 TerminalDevice = AllocateCopyPool (sizeof (TERMINAL_DEV), &mTerminalDevTemplate);
639 if (TerminalDevice == NULL) {
640 Status = EFI_OUT_OF_RESOURCES;
641 goto Error;
642 }
643
644 TerminalDevice->TerminalType = TerminalType;
645 TerminalDevice->SerialIo = SerialIo;
646
647 InitializeListHead (&TerminalDevice->NotifyList);
648 Status = gBS->CreateEvent (
649 EVT_NOTIFY_WAIT,
650 TPL_NOTIFY,
651 TerminalConInWaitForKeyEx,
652 TerminalDevice,
653 &TerminalDevice->SimpleInputEx.WaitForKeyEx
654 );
655 if (EFI_ERROR (Status)) {
656 goto Error;
657 }
658
659 Status = gBS->CreateEvent (
660 EVT_NOTIFY_WAIT,
661 TPL_NOTIFY,
662 TerminalConInWaitForKey,
663 TerminalDevice,
664 &TerminalDevice->SimpleInput.WaitForKey
665 );
666 if (EFI_ERROR (Status)) {
667 goto Error;
668 }
669 //
670 // Allocates and initializes the FIFO buffer to be zero, used for accommodating
671 // the pre-read pending characters.
672 //
673 TerminalDevice->RawFiFo = AllocateZeroPool (sizeof (RAW_DATA_FIFO));
674 if (TerminalDevice->RawFiFo == NULL) {
675 goto Error;
676 }
677 TerminalDevice->UnicodeFiFo = AllocateZeroPool (sizeof (UNICODE_FIFO));
678 if (TerminalDevice->UnicodeFiFo == NULL) {
679 goto Error;
680 }
681 TerminalDevice->EfiKeyFiFo = AllocateZeroPool (sizeof (EFI_KEY_FIFO));
682 if (TerminalDevice->EfiKeyFiFo == NULL) {
683 goto Error;
684 }
685
686 //
687 // Set the timeout value of serial buffer for
688 // keystroke response performance issue
689 //
690 Mode = TerminalDevice->SerialIo->Mode;
691
692 SerialInTimeOut = 0;
693 if (Mode->BaudRate != 0) {
694 SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate;
695 }
696
697 Status = TerminalDevice->SerialIo->SetAttributes (
698 TerminalDevice->SerialIo,
699 Mode->BaudRate,
700 Mode->ReceiveFifoDepth,
701 (UINT32) SerialInTimeOut,
702 (EFI_PARITY_TYPE) (Mode->Parity),
703 (UINT8) Mode->DataBits,
704 (EFI_STOP_BITS_TYPE) (Mode->StopBits)
705 );
706 if (EFI_ERROR (Status)) {
707 //
708 // if set attributes operation fails, invalidate
709 // the value of SerialInTimeOut,thus make it
710 // inconsistent with the default timeout value
711 // of serial buffer. This will invoke the recalculation
712 // in the readkeystroke routine.
713 //
714 TerminalDevice->SerialInTimeOut = 0;
715 } else {
716 TerminalDevice->SerialInTimeOut = SerialInTimeOut;
717 }
718 //
719 // Set Simple Text Output Protocol from template.
720 //
721 SimpleTextOutput = CopyMem (
722 &TerminalDevice->SimpleTextOutput,
723 &mTerminalDevTemplate.SimpleTextOutput,
724 sizeof (mTerminalDevTemplate.SimpleTextOutput)
725 );
726 SimpleTextOutput->Mode = &TerminalDevice->SimpleTextOutputMode;
727
728 TerminalDevice->SimpleTextOutputMode.MaxMode = TERMINAL_MAX_MODE;
729 //
730 // For terminal devices, cursor is always visible
731 //
732 TerminalDevice->SimpleTextOutputMode.CursorVisible = TRUE;
733 Status = TerminalConOutSetAttribute (
734 SimpleTextOutput,
735 EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)
736 );
737 if (EFI_ERROR (Status)) {
738 goto ReportError;
739 }
740
741 //
742 // Build the component name for the child device
743 //
744 TerminalDevice->ControllerNameTable = NULL;
745 switch (TerminalDevice->TerminalType) {
746 case PCANSITYPE:
747 AddUnicodeString2 (
748 "eng",
749 gTerminalComponentName.SupportedLanguages,
750 &TerminalDevice->ControllerNameTable,
751 (CHAR16 *)L"PC-ANSI Serial Console",
752 TRUE
753 );
754 AddUnicodeString2 (
755 "en",
756 gTerminalComponentName2.SupportedLanguages,
757 &TerminalDevice->ControllerNameTable,
758 (CHAR16 *)L"PC-ANSI Serial Console",
759 FALSE
760 );
761
762 break;
763
764 case VT100TYPE:
765 AddUnicodeString2 (
766 "eng",
767 gTerminalComponentName.SupportedLanguages,
768 &TerminalDevice->ControllerNameTable,
769 (CHAR16 *)L"VT-100 Serial Console",
770 TRUE
771 );
772 AddUnicodeString2 (
773 "en",
774 gTerminalComponentName2.SupportedLanguages,
775 &TerminalDevice->ControllerNameTable,
776 (CHAR16 *)L"VT-100 Serial Console",
777 FALSE
778 );
779
780 break;
781
782 case VT100PLUSTYPE:
783 AddUnicodeString2 (
784 "eng",
785 gTerminalComponentName.SupportedLanguages,
786 &TerminalDevice->ControllerNameTable,
787 (CHAR16 *)L"VT-100+ Serial Console",
788 TRUE
789 );
790 AddUnicodeString2 (
791 "en",
792 gTerminalComponentName2.SupportedLanguages,
793 &TerminalDevice->ControllerNameTable,
794 (CHAR16 *)L"VT-100+ Serial Console",
795 FALSE
796 );
797
798 break;
799
800 case VTUTF8TYPE:
801 AddUnicodeString2 (
802 "eng",
803 gTerminalComponentName.SupportedLanguages,
804 &TerminalDevice->ControllerNameTable,
805 (CHAR16 *)L"VT-UTF8 Serial Console",
806 TRUE
807 );
808 AddUnicodeString2 (
809 "en",
810 gTerminalComponentName2.SupportedLanguages,
811 &TerminalDevice->ControllerNameTable,
812 (CHAR16 *)L"VT-UTF8 Serial Console",
813 FALSE
814 );
815
816 break;
817 }
818
819 //
820 // Build the device path for the child device
821 //
822 Status = SetTerminalDevicePath (
823 TerminalDevice->TerminalType,
824 ParentDevicePath,
825 &TerminalDevice->DevicePath
826 );
827 if (EFI_ERROR (Status)) {
828 goto Error;
829 }
830
831 Status = TerminalConOutReset (SimpleTextOutput, FALSE);
832 if (EFI_ERROR (Status)) {
833 goto ReportError;
834 }
835
836 Status = TerminalConOutSetMode (SimpleTextOutput, 0);
837 if (EFI_ERROR (Status)) {
838 goto ReportError;
839 }
840
841 Status = TerminalConOutEnableCursor (SimpleTextOutput, TRUE);
842 if (EFI_ERROR (Status)) {
843 goto ReportError;
844 }
845
846 Status = gBS->CreateEvent (
847 EVT_TIMER | EVT_NOTIFY_SIGNAL,
848 TPL_NOTIFY,
849 TerminalConInTimerHandler,
850 TerminalDevice,
851 &TerminalDevice->TimerEvent
852 );
853 ASSERT_EFI_ERROR (Status);
854
855 Status = gBS->SetTimer (
856 TerminalDevice->TimerEvent,
857 TimerPeriodic,
858 KEYBOARD_TIMER_INTERVAL
859 );
860 ASSERT_EFI_ERROR (Status);
861
862 Status = gBS->CreateEvent (
863 EVT_TIMER,
864 TPL_CALLBACK,
865 NULL,
866 NULL,
867 &TerminalDevice->TwoSecondTimeOut
868 );
869 ASSERT_EFI_ERROR (Status);
870
871 Status = gBS->InstallProtocolInterface (
872 &TerminalDevice->Handle,
873 &gEfiDevicePathProtocolGuid,
874 EFI_NATIVE_INTERFACE,
875 TerminalDevice->DevicePath
876 );
877 if (EFI_ERROR (Status)) {
878 goto Error;
879 }
880
881 //
882 // Register the Parent-Child relationship via
883 // EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
884 //
885 Status = gBS->OpenProtocol (
886 Controller,
887 &gEfiSerialIoProtocolGuid,
888 (VOID **) &TerminalDevice->SerialIo,
889 This->DriverBindingHandle,
890 TerminalDevice->Handle,
891 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
892 );
893 if (EFI_ERROR (Status)) {
894 goto Error;
895 }
896 }
897
898 //
899 // Find the child handle, and get its TerminalDevice private data
900 //
901 Status = gBS->OpenProtocolInformation (
902 Controller,
903 &gEfiSerialIoProtocolGuid,
904 &OpenInfoBuffer,
905 &EntryCount
906 );
907 if (!EFI_ERROR (Status)) {
908 Status = EFI_NOT_FOUND;
909 ASSERT (OpenInfoBuffer != NULL);
910 for (Index = 0; Index < EntryCount; Index++) {
911 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
912 //
913 // Find the child terminal handle.
914 // Test whether the SimpleTxtIn and SimpleTxtOut have been published
915 //
916 Status = gBS->OpenProtocol (
917 OpenInfoBuffer[Index].ControllerHandle,
918 &gEfiSimpleTextInProtocolGuid,
919 (VOID **) &SimpleTextInput,
920 This->DriverBindingHandle,
921 OpenInfoBuffer[Index].ControllerHandle,
922 EFI_OPEN_PROTOCOL_GET_PROTOCOL
923 );
924 if (!EFI_ERROR (Status)) {
925 SimTxtInInstalled = TRUE;
926 TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (SimpleTextInput);
927 }
928
929 Status = gBS->OpenProtocol (
930 OpenInfoBuffer[Index].ControllerHandle,
931 &gEfiSimpleTextOutProtocolGuid,
932 (VOID **) &SimpleTextOutput,
933 This->DriverBindingHandle,
934 OpenInfoBuffer[Index].ControllerHandle,
935 EFI_OPEN_PROTOCOL_GET_PROTOCOL
936 );
937 if (!EFI_ERROR (Status)) {
938 SimTxtOutInstalled = TRUE;
939 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);
940 }
941 Status = EFI_SUCCESS;
942 break;
943 }
944 }
945
946 FreePool (OpenInfoBuffer);
947 if (EFI_ERROR (Status)) {
948 goto ReportError;
949 }
950 } else {
951 goto ReportError;
952 }
953
954 ASSERT (TerminalDevice != NULL);
955 //
956 // Only do the reset if the device path is in the Conout variable
957 //
958 if (ConInSelected && !SimTxtInInstalled) {
959 Status = TerminalDevice->SimpleInput.Reset (
960 &TerminalDevice->SimpleInput,
961 FALSE
962 );
963 if (EFI_ERROR (Status)) {
964 //
965 // Need to report Error Code first
966 //
967 goto ReportError;
968 }
969 }
970
971 //
972 // Only output the configure string to remote terminal if the device path
973 // is in the Conout variable
974 //
975 if (ConOutSelected && !SimTxtOutInstalled) {
976 Status = TerminalDevice->SimpleTextOutput.SetAttribute (
977 &TerminalDevice->SimpleTextOutput,
978 EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)
979 );
980 if (EFI_ERROR (Status)) {
981 goto ReportError;
982 }
983
984 Status = TerminalDevice->SimpleTextOutput.Reset (
985 &TerminalDevice->SimpleTextOutput,
986 FALSE
987 );
988 if (EFI_ERROR (Status)) {
989 goto ReportError;
990 }
991
992 Status = TerminalDevice->SimpleTextOutput.SetMode (
993 &TerminalDevice->SimpleTextOutput,
994 0
995 );
996 if (EFI_ERROR (Status)) {
997 goto ReportError;
998 }
999
1000 Status = TerminalDevice->SimpleTextOutput.EnableCursor (
1001 &TerminalDevice->SimpleTextOutput,
1002 TRUE
1003 );
1004 if (EFI_ERROR (Status)) {
1005 goto ReportError;
1006 }
1007 }
1008
1009 //
1010 // Simple In/Out Protocol will not be installed onto the handle if the
1011 // device path to the handle is not present in the ConIn/ConOut
1012 // environment variable. But If RemainingDevicePath is NULL, then always
1013 // produce both Simple In and Simple Text Output Protocols. This is required
1014 // for the connect all sequences to make sure all possible consoles are
1015 // produced no matter what the current values of ConIn, ConOut, or StdErr are.
1016 //
1017 if (!SimTxtInInstalled && (ConInSelected || NullRemaining)) {
1018 Status = gBS->InstallMultipleProtocolInterfaces (
1019 &TerminalDevice->Handle,
1020 &gEfiSimpleTextInProtocolGuid,
1021 &TerminalDevice->SimpleInput,
1022 &gEfiSimpleTextInputExProtocolGuid,
1023 &TerminalDevice->SimpleInputEx,
1024 NULL
1025 );
1026 if (EFI_ERROR (Status)) {
1027 goto Error;
1028 }
1029 }
1030
1031 if (!SimTxtOutInstalled && (ConOutSelected || NullRemaining)) {
1032 Status = gBS->InstallProtocolInterface (
1033 &TerminalDevice->Handle,
1034 &gEfiSimpleTextOutProtocolGuid,
1035 EFI_NATIVE_INTERFACE,
1036 &TerminalDevice->SimpleTextOutput
1037 );
1038 if (EFI_ERROR (Status)) {
1039 goto Error;
1040 }
1041 }
1042 if (DefaultNode != NULL) {
1043 FreePool (DefaultNode);
1044 }
1045
1046 return EFI_SUCCESS;
1047
1048 ReportError:
1049 //
1050 // Report error code before exiting
1051 //
1052 DevicePath = ParentDevicePath;
1053 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1054 EFI_ERROR_CODE | EFI_ERROR_MINOR,
1055 (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),
1056 DevicePath
1057 );
1058
1059 Error:
1060 //
1061 // Use the Stop() function to free all resources allocated in Start()
1062 //
1063 if (TerminalDevice != NULL) {
1064
1065 if (TerminalDevice->Handle != NULL) {
1066 This->Stop (This, Controller, 1, &TerminalDevice->Handle);
1067 } else {
1068
1069 if (TerminalDevice->TwoSecondTimeOut != NULL) {
1070 gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);
1071 }
1072
1073 if (TerminalDevice->TimerEvent != NULL) {
1074 gBS->CloseEvent (TerminalDevice->TimerEvent);
1075 }
1076
1077 if (TerminalDevice->SimpleInput.WaitForKey != NULL) {
1078 gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);
1079 }
1080
1081 if (TerminalDevice->SimpleInputEx.WaitForKeyEx != NULL) {
1082 gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);
1083 }
1084
1085 TerminalFreeNotifyList (&TerminalDevice->NotifyList);
1086
1087 if (TerminalDevice->RawFiFo != NULL) {
1088 FreePool (TerminalDevice->RawFiFo);
1089 }
1090 if (TerminalDevice->UnicodeFiFo != NULL) {
1091 FreePool (TerminalDevice->UnicodeFiFo);
1092 }
1093 if (TerminalDevice->EfiKeyFiFo != NULL) {
1094 FreePool (TerminalDevice->EfiKeyFiFo);
1095 }
1096
1097 if (TerminalDevice->ControllerNameTable != NULL) {
1098 FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
1099 }
1100
1101 if (TerminalDevice->DevicePath != NULL) {
1102 FreePool (TerminalDevice->DevicePath);
1103 }
1104
1105 FreePool (TerminalDevice);
1106 }
1107 }
1108
1109 if (DefaultNode != NULL) {
1110 FreePool (DefaultNode);
1111 }
1112
1113 This->Stop (This, Controller, 0, NULL);
1114
1115 return Status;
1116 }
1117
1118 /**
1119 Stop this driver on Controller by closing Simple Text In, Simple Text
1120 In Ex, Simple Text Out protocol, and removing parent device path from
1121 Console Device Environment Variables.
1122
1123 @param This Protocol instance pointer.
1124 @param Controller Handle of device to stop driver on
1125 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
1126 children is zero stop the entire bus driver.
1127 @param ChildHandleBuffer List of Child Handles to Stop.
1128
1129 @retval EFI_SUCCESS This driver is removed Controller.
1130 @retval other This driver could not be removed from this device.
1131
1132 **/
1133 EFI_STATUS
1134 EFIAPI
1135 TerminalDriverBindingStop (
1136 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1137 IN EFI_HANDLE Controller,
1138 IN UINTN NumberOfChildren,
1139 IN EFI_HANDLE *ChildHandleBuffer
1140 )
1141 {
1142 EFI_STATUS Status;
1143 UINTN Index;
1144 BOOLEAN AllChildrenStopped;
1145 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;
1146 TERMINAL_DEV *TerminalDevice;
1147 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
1148 EFI_SERIAL_IO_PROTOCOL *SerialIo;
1149 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1150
1151 Status = gBS->HandleProtocol (
1152 Controller,
1153 &gEfiDevicePathProtocolGuid,
1154 (VOID **) &DevicePath
1155 );
1156 if (EFI_ERROR (Status)) {
1157 return Status;
1158 }
1159
1160 //
1161 // Complete all outstanding transactions to Controller.
1162 // Don't allow any new transaction to Controller to be started.
1163 //
1164 if (NumberOfChildren == 0) {
1165 //
1166 // Close the bus driver
1167 //
1168 Status = gBS->OpenProtocol (
1169 Controller,
1170 &gEfiCallerIdGuid,
1171 (VOID **) &ParentDevicePath,
1172 This->DriverBindingHandle,
1173 Controller,
1174 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1175 );
1176 if (!EFI_ERROR (Status)) {
1177 //
1178 // Remove Parent Device Path from
1179 // the Console Device Environment Variables
1180 //
1181 TerminalRemoveConsoleDevVariable (L"ConInDev", ParentDevicePath);
1182 TerminalRemoveConsoleDevVariable (L"ConOutDev", ParentDevicePath);
1183 TerminalRemoveConsoleDevVariable (L"ErrOutDev", ParentDevicePath);
1184
1185 //
1186 // Uninstall the Terminal Driver's GUID Tag from the Serial controller
1187 //
1188 Status = gBS->UninstallMultipleProtocolInterfaces (
1189 Controller,
1190 &gEfiCallerIdGuid,
1191 ParentDevicePath,
1192 NULL
1193 );
1194
1195 //
1196 // Free the ParentDevicePath that was duplicated in Start()
1197 //
1198 if (!EFI_ERROR (Status)) {
1199 FreePool (ParentDevicePath);
1200 }
1201 }
1202
1203 gBS->CloseProtocol (
1204 Controller,
1205 &gEfiSerialIoProtocolGuid,
1206 This->DriverBindingHandle,
1207 Controller
1208 );
1209
1210 gBS->CloseProtocol (
1211 Controller,
1212 &gEfiDevicePathProtocolGuid,
1213 This->DriverBindingHandle,
1214 Controller
1215 );
1216
1217 return EFI_SUCCESS;
1218 }
1219
1220 AllChildrenStopped = TRUE;
1221
1222 for (Index = 0; Index < NumberOfChildren; Index++) {
1223
1224 Status = gBS->OpenProtocol (
1225 ChildHandleBuffer[Index],
1226 &gEfiSimpleTextOutProtocolGuid,
1227 (VOID **) &SimpleTextOutput,
1228 This->DriverBindingHandle,
1229 ChildHandleBuffer[Index],
1230 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1231 );
1232 if (!EFI_ERROR (Status)) {
1233
1234 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);
1235
1236 gBS->CloseProtocol (
1237 Controller,
1238 &gEfiSerialIoProtocolGuid,
1239 This->DriverBindingHandle,
1240 ChildHandleBuffer[Index]
1241 );
1242
1243 Status = gBS->UninstallMultipleProtocolInterfaces (
1244 ChildHandleBuffer[Index],
1245 &gEfiSimpleTextInProtocolGuid,
1246 &TerminalDevice->SimpleInput,
1247 &gEfiSimpleTextInputExProtocolGuid,
1248 &TerminalDevice->SimpleInputEx,
1249 &gEfiSimpleTextOutProtocolGuid,
1250 &TerminalDevice->SimpleTextOutput,
1251 &gEfiDevicePathProtocolGuid,
1252 TerminalDevice->DevicePath,
1253 NULL
1254 );
1255 if (EFI_ERROR (Status)) {
1256 gBS->OpenProtocol (
1257 Controller,
1258 &gEfiSerialIoProtocolGuid,
1259 (VOID **) &SerialIo,
1260 This->DriverBindingHandle,
1261 ChildHandleBuffer[Index],
1262 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1263 );
1264 } else {
1265
1266 if (TerminalDevice->ControllerNameTable != NULL) {
1267 FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
1268 }
1269
1270 gBS->CloseEvent (TerminalDevice->TimerEvent);
1271 gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);
1272 gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);
1273 gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);
1274 TerminalFreeNotifyList (&TerminalDevice->NotifyList);
1275 FreePool (TerminalDevice->DevicePath);
1276 FreePool (TerminalDevice);
1277 }
1278 }
1279
1280 if (EFI_ERROR (Status)) {
1281 AllChildrenStopped = FALSE;
1282 }
1283 }
1284
1285 if (!AllChildrenStopped) {
1286 return EFI_DEVICE_ERROR;
1287 }
1288
1289 return EFI_SUCCESS;
1290 }
1291
1292 /**
1293 Update terminal device path in Console Device Environment Variables.
1294
1295 @param VariableName The Console Device Environment Variable.
1296 @param ParentDevicePath The terminal device path to be updated.
1297
1298 **/
1299 VOID
1300 TerminalUpdateConsoleDevVariable (
1301 IN CHAR16 *VariableName,
1302 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
1303 )
1304 {
1305 EFI_STATUS Status;
1306 UINTN VariableSize;
1307 UINT8 TerminalType;
1308 EFI_DEVICE_PATH_PROTOCOL *Variable;
1309 EFI_DEVICE_PATH_PROTOCOL *NewVariable;
1310 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1311
1312 //
1313 // Get global variable and its size according to the name given.
1314 //
1315 Variable = GetEfiGlobalVariable (VariableName);
1316 if (Variable == NULL) {
1317 return;
1318 }
1319
1320 //
1321 // Append terminal device path onto the variable.
1322 //
1323 for (TerminalType = PCANSITYPE; TerminalType <= VTUTF8TYPE; TerminalType++) {
1324 SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);
1325 NewVariable = AppendDevicePathInstance (Variable, TempDevicePath);
1326 if (Variable != NULL) {
1327 FreePool (Variable);
1328 }
1329
1330 if (TempDevicePath != NULL) {
1331 FreePool (TempDevicePath);
1332 }
1333
1334 Variable = NewVariable;
1335 }
1336
1337 VariableSize = GetDevicePathSize (Variable);
1338
1339 Status = gRT->SetVariable (
1340 VariableName,
1341 &gEfiGlobalVariableGuid,
1342 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
1343 VariableSize,
1344 Variable
1345 );
1346 ASSERT_EFI_ERROR (Status);
1347 FreePool (Variable);
1348
1349 return ;
1350 }
1351
1352
1353 /**
1354 Remove terminal device path from Console Device Environment Variables.
1355
1356 @param VariableName Console Device Environment Variables.
1357 @param ParentDevicePath The terminal device path to be updated.
1358
1359 **/
1360 VOID
1361 TerminalRemoveConsoleDevVariable (
1362 IN CHAR16 *VariableName,
1363 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
1364 )
1365 {
1366 EFI_STATUS Status;
1367 BOOLEAN FoundOne;
1368 BOOLEAN Match;
1369 UINTN VariableSize;
1370 UINTN InstanceSize;
1371 UINT8 TerminalType;
1372 EFI_DEVICE_PATH_PROTOCOL *Instance;
1373 EFI_DEVICE_PATH_PROTOCOL *Variable;
1374 EFI_DEVICE_PATH_PROTOCOL *OriginalVariable;
1375 EFI_DEVICE_PATH_PROTOCOL *NewVariable;
1376 EFI_DEVICE_PATH_PROTOCOL *SavedNewVariable;
1377 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1378
1379 Instance = NULL;
1380
1381 //
1382 // Get global variable and its size according to the name given.
1383 //
1384 Variable = GetEfiGlobalVariable (VariableName);
1385 if (Variable == NULL) {
1386 return ;
1387 }
1388
1389 FoundOne = FALSE;
1390 OriginalVariable = Variable;
1391 NewVariable = NULL;
1392
1393 //
1394 // Get first device path instance from Variable
1395 //
1396 Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);
1397 if (Instance == NULL) {
1398 FreePool (OriginalVariable);
1399 return ;
1400 }
1401 //
1402 // Loop through all the device path instances of Variable
1403 //
1404 do {
1405 //
1406 // Loop through all the terminal types that this driver supports
1407 //
1408 Match = FALSE;
1409 for (TerminalType = PCANSITYPE; TerminalType <= VTUTF8TYPE; TerminalType++) {
1410
1411 SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);
1412
1413 //
1414 // Compare the generated device path to the current device path instance
1415 //
1416 if (TempDevicePath != NULL) {
1417 if (CompareMem (Instance, TempDevicePath, InstanceSize) == 0) {
1418 Match = TRUE;
1419 FoundOne = TRUE;
1420 }
1421
1422 FreePool (TempDevicePath);
1423 }
1424 }
1425 //
1426 // If a match was not found, then keep the current device path instance
1427 //
1428 if (!Match) {
1429 SavedNewVariable = NewVariable;
1430 NewVariable = AppendDevicePathInstance (NewVariable, Instance);
1431 if (SavedNewVariable != NULL) {
1432 FreePool (SavedNewVariable);
1433 }
1434 }
1435 //
1436 // Get next device path instance from Variable
1437 //
1438 FreePool (Instance);
1439 Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);
1440 } while (Instance != NULL);
1441
1442 FreePool (OriginalVariable);
1443
1444 if (FoundOne) {
1445 VariableSize = GetDevicePathSize (NewVariable);
1446
1447 Status = gRT->SetVariable (
1448 VariableName,
1449 &gEfiGlobalVariableGuid,
1450 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
1451 VariableSize,
1452 NewVariable
1453 );
1454 ASSERT_EFI_ERROR (Status);
1455 }
1456
1457 if (NewVariable != NULL) {
1458 FreePool (NewVariable);
1459 }
1460
1461 return ;
1462 }
1463
1464 /**
1465 Build terminal device path according to terminal type.
1466
1467 @param TerminalType The terminal type is PC ANSI, VT100, VT100+ or VT-UTF8.
1468 @param ParentDevicePath Parent device path.
1469 @param TerminalDevicePath Returned terminal device path, if building successfully.
1470
1471 @retval EFI_UNSUPPORTED Terminal does not belong to the supported type.
1472 @retval EFI_OUT_OF_RESOURCES Generate terminal device path failed.
1473 @retval EFI_SUCCESS Build terminal device path successfully.
1474
1475 **/
1476 EFI_STATUS
1477 SetTerminalDevicePath (
1478 IN UINT8 TerminalType,
1479 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
1480 OUT EFI_DEVICE_PATH_PROTOCOL **TerminalDevicePath
1481 )
1482 {
1483 VENDOR_DEVICE_PATH Node;
1484
1485 *TerminalDevicePath = NULL;
1486 Node.Header.Type = MESSAGING_DEVICE_PATH;
1487 Node.Header.SubType = MSG_VENDOR_DP;
1488
1489 //
1490 // Generate terminal device path node according to terminal type.
1491 //
1492 switch (TerminalType) {
1493
1494 case PCANSITYPE:
1495 CopyGuid (&Node.Guid, &gEfiPcAnsiGuid);
1496 break;
1497
1498 case VT100TYPE:
1499 CopyGuid (&Node.Guid, &gEfiVT100Guid);
1500 break;
1501
1502 case VT100PLUSTYPE:
1503 CopyGuid (&Node.Guid, &gEfiVT100PlusGuid);
1504 break;
1505
1506 case VTUTF8TYPE:
1507 CopyGuid (&Node.Guid, &gEfiVTUTF8Guid);
1508 break;
1509
1510 default:
1511 return EFI_UNSUPPORTED;
1512 }
1513
1514 //
1515 // Get VENDOR_DEVCIE_PATH size and put into Node.Header
1516 //
1517 SetDevicePathNodeLength (
1518 &Node.Header,
1519 sizeof (VENDOR_DEVICE_PATH)
1520 );
1521
1522 //
1523 // Append the terminal node onto parent device path
1524 // to generate a complete terminal device path.
1525 //
1526 *TerminalDevicePath = AppendDevicePathNode (
1527 ParentDevicePath,
1528 (EFI_DEVICE_PATH_PROTOCOL *) &Node
1529 );
1530 if (*TerminalDevicePath == NULL) {
1531 return EFI_OUT_OF_RESOURCES;
1532 }
1533
1534 return EFI_SUCCESS;
1535 }
1536
1537 /**
1538 The user Entry Point for module Terminal. The user code starts with this function.
1539
1540 @param ImageHandle The firmware allocated handle for the EFI image.
1541 @param SystemTable A pointer to the EFI System Table.
1542
1543 @retval EFI_SUCCESS The entry point is executed successfully.
1544 @retval other Some error occurs when executing this entry point.
1545
1546 **/
1547 EFI_STATUS
1548 EFIAPI
1549 InitializeTerminal(
1550 IN EFI_HANDLE ImageHandle,
1551 IN EFI_SYSTEM_TABLE *SystemTable
1552 )
1553 {
1554 EFI_STATUS Status;
1555
1556 //
1557 // Install driver model protocol(s).
1558 //
1559 Status = EfiLibInstallDriverBindingComponentName2 (
1560 ImageHandle,
1561 SystemTable,
1562 &gTerminalDriverBinding,
1563 ImageHandle,
1564 &gTerminalComponentName,
1565 &gTerminalComponentName2
1566 );
1567 ASSERT_EFI_ERROR (Status);
1568
1569 return Status;
1570 }
1571
1572 /**
1573 Check if the device supports hot-plug through its device path.
1574
1575 This function could be updated to check more types of Hot Plug devices.
1576 Currently, it checks USB and PCCard device.
1577
1578 @param DevicePath Pointer to device's device path.
1579
1580 @retval TRUE The devcie is a hot-plug device
1581 @retval FALSE The devcie is not a hot-plug device.
1582
1583 **/
1584 BOOLEAN
1585 IsHotPlugDevice (
1586 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
1587 )
1588 {
1589 EFI_DEVICE_PATH_PROTOCOL *CheckDevicePath;
1590
1591 CheckDevicePath = DevicePath;
1592 while (!IsDevicePathEnd (CheckDevicePath)) {
1593 //
1594 // Check device whether is hot plug device or not throught Device Path
1595 //
1596 if ((DevicePathType (CheckDevicePath) == MESSAGING_DEVICE_PATH) &&
1597 (DevicePathSubType (CheckDevicePath) == MSG_USB_DP ||
1598 DevicePathSubType (CheckDevicePath) == MSG_USB_CLASS_DP ||
1599 DevicePathSubType (CheckDevicePath) == MSG_USB_WWID_DP)) {
1600 //
1601 // If Device is USB device
1602 //
1603 return TRUE;
1604 }
1605 if ((DevicePathType (CheckDevicePath) == HARDWARE_DEVICE_PATH) &&
1606 (DevicePathSubType (CheckDevicePath) == HW_PCCARD_DP)) {
1607 //
1608 // If Device is PCCard
1609 //
1610 return TRUE;
1611 }
1612
1613 CheckDevicePath = NextDevicePathNode (CheckDevicePath);
1614 }
1615
1616 return FALSE;
1617 }
1618