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