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