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