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