Cleaned up EFI Console Variable usage
[mirror_edk2.git] / MdeModulePkg / Universal / Console / TerminalDxe / Terminal.c
1 /*++
2
3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 Terminal.c
15
16 Abstract:
17
18 Revision History:
19
20 --*/
21
22
23 #include "Terminal.h"
24
25 //
26 // Globals
27 //
28 EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding = {
29 TerminalDriverBindingSupported,
30 TerminalDriverBindingStart,
31 TerminalDriverBindingStop,
32 0xa,
33 NULL,
34 NULL
35 };
36
37
38 EFI_GUID *gTerminalType[] = {
39 &gEfiPcAnsiGuid,
40 &gEfiVT100Guid,
41 &gEfiVT100PlusGuid,
42 &gEfiVTUTF8Guid
43 };
44
45
46 TERMINAL_DEV gTerminalDevTemplate = {
47 TERMINAL_DEV_SIGNATURE,
48 NULL,
49 0,
50 NULL,
51 NULL,
52 { // SimpleTextInput
53 TerminalConInReset,
54 TerminalConInReadKeyStroke,
55 NULL
56 },
57 { // SimpleTextOutput
58 TerminalConOutReset,
59 TerminalConOutOutputString,
60 TerminalConOutTestString,
61 TerminalConOutQueryMode,
62 TerminalConOutSetMode,
63 TerminalConOutSetAttribute,
64 TerminalConOutClearScreen,
65 TerminalConOutSetCursorPosition,
66 TerminalConOutEnableCursor,
67 NULL
68 },
69 { // SimpleTextOutputMode
70 1, // MaxMode
71 0, // Mode?
72 EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK), // Attribute
73 0, // CursorColumn
74 0, // CursorRow
75 TRUE // CursorVisible
76 },
77 0,
78 {
79 0,
80 0,
81 { 0 }
82 },
83 {
84 0,
85 0,
86 { 0 }
87 },
88 {
89 0,
90 0,
91 { 0 }
92 },
93 NULL, // ControllerNameTable
94 NULL,
95 INPUT_STATE_DEFAULT,
96 RESET_STATE_DEFAULT,
97 FALSE
98 };
99
100
101
102 EFI_STATUS
103 EFIAPI
104 TerminalDriverBindingSupported (
105 IN EFI_DRIVER_BINDING_PROTOCOL *This,
106 IN EFI_HANDLE Controller,
107 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
108 )
109 {
110 EFI_STATUS Status;
111 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
112 EFI_SERIAL_IO_PROTOCOL *SerialIo;
113 VENDOR_DEVICE_PATH *Node;
114
115 //
116 // If remaining device path is not NULL, then make sure it is a
117 // device path that describes a terminal communications protocol.
118 //
119 if (RemainingDevicePath != NULL) {
120
121 Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;
122
123 if (Node->Header.Type != MESSAGING_DEVICE_PATH ||
124 Node->Header.SubType != MSG_VENDOR_DP ||
125 DevicePathNodeLength(&Node->Header) != sizeof(VENDOR_DEVICE_PATH)) {
126
127 return EFI_UNSUPPORTED;
128
129 }
130 //
131 // only supports PC ANSI, VT100, VT100+ and VT-UTF8 terminal types
132 //
133 if (!CompareGuid (&Node->Guid, &gEfiPcAnsiGuid) &&
134 !CompareGuid (&Node->Guid, &gEfiVT100Guid) &&
135 !CompareGuid (&Node->Guid, &gEfiVT100PlusGuid) &&
136 !CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {
137
138 return EFI_UNSUPPORTED;
139 }
140 }
141 //
142 // Open the IO Abstraction(s) needed to perform the supported test
143 //
144 Status = gBS->OpenProtocol (
145 Controller,
146 &gEfiDevicePathProtocolGuid,
147 (VOID **) &ParentDevicePath,
148 This->DriverBindingHandle,
149 Controller,
150 EFI_OPEN_PROTOCOL_BY_DRIVER
151 );
152 if (Status == EFI_ALREADY_STARTED) {
153 return EFI_SUCCESS;
154 }
155
156 if (EFI_ERROR (Status)) {
157 return Status;
158 }
159
160 gBS->CloseProtocol (
161 Controller,
162 &gEfiDevicePathProtocolGuid,
163 This->DriverBindingHandle,
164 Controller
165 );
166
167 //
168 // The Controller must support the Serial I/O Protocol.
169 // This driver is a bus driver with at most 1 child device, so it is
170 // ok for it to be already started.
171 //
172 Status = gBS->OpenProtocol (
173 Controller,
174 &gEfiSerialIoProtocolGuid,
175 (VOID **) &SerialIo,
176 This->DriverBindingHandle,
177 Controller,
178 EFI_OPEN_PROTOCOL_BY_DRIVER
179 );
180 if (Status == EFI_ALREADY_STARTED) {
181 return EFI_SUCCESS;
182 }
183
184 if (EFI_ERROR (Status)) {
185 return Status;
186 }
187 //
188 // Close the I/O Abstraction(s) used to perform the supported test
189 //
190 gBS->CloseProtocol (
191 Controller,
192 &gEfiSerialIoProtocolGuid,
193 This->DriverBindingHandle,
194 Controller
195 );
196
197 return Status;
198 }
199
200 EFI_STATUS
201 EFIAPI
202 TerminalDriverBindingStart (
203 IN EFI_DRIVER_BINDING_PROTOCOL *This,
204 IN EFI_HANDLE Controller,
205 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
206 )
207 /*++
208
209 Routine Description:
210
211 Start the controller.
212
213 Arguments:
214
215 This - A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
216 Controller - The handle of the controller to start.
217 RemainingDevicePath - A pointer to the remaining portion of a devcie path.
218
219 Returns:
220
221 EFI_SUCCESS.
222
223 --*/
224 {
225 EFI_STATUS Status;
226 EFI_SERIAL_IO_PROTOCOL *SerialIo;
227 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
228 VENDOR_DEVICE_PATH *Node;
229 VENDOR_DEVICE_PATH *DefaultNode;
230 EFI_SERIAL_IO_MODE *Mode;
231 UINTN SerialInTimeOut;
232 TERMINAL_DEV *TerminalDevice;
233 UINT8 TerminalType;
234 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
235 UINTN EntryCount;
236 UINTN Index;
237 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
238
239 TerminalDevice = NULL;
240 DefaultNode = NULL;
241 //
242 // Get the Device Path Protocol to build the device path of the child device
243 //
244 Status = gBS->OpenProtocol (
245 Controller,
246 &gEfiDevicePathProtocolGuid,
247 (VOID **) &ParentDevicePath,
248 This->DriverBindingHandle,
249 Controller,
250 EFI_OPEN_PROTOCOL_BY_DRIVER
251 );
252 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
253 return Status;
254 }
255
256 //
257 // Open the Serial I/O Protocol BY_DRIVER. It might already be started.
258 //
259 Status = gBS->OpenProtocol (
260 Controller,
261 &gEfiSerialIoProtocolGuid,
262 (VOID **) &SerialIo,
263 This->DriverBindingHandle,
264 Controller,
265 EFI_OPEN_PROTOCOL_BY_DRIVER
266 );
267 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
268 return Status;
269 }
270
271 if (Status != EFI_ALREADY_STARTED) {
272 //
273 // If Serial I/O is not already open by this driver, then tag the handle
274 // with the Terminal Driver GUID and update the ConInDev, ConOutDev, and
275 // StdErrDev variables with the list of possible terminal types on this
276 // serial port.
277 //
278 Status = gBS->OpenProtocol (
279 Controller,
280 &gEfiCallerIdGuid,
281 NULL,
282 This->DriverBindingHandle,
283 Controller,
284 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
285 );
286 if (EFI_ERROR (Status)) {
287 Status = gBS->InstallMultipleProtocolInterfaces (
288 &Controller,
289 &gEfiCallerIdGuid,
290 DuplicateDevicePath (ParentDevicePath),
291 NULL
292 );
293 if (EFI_ERROR (Status)) {
294 goto Error;
295 }
296 //
297 // if the serial device is a hot plug device, do not update the
298 // ConInDev, ConOutDev, and StdErrDev variables.
299 //
300 Status = gBS->OpenProtocol (
301 Controller,
302 &gEfiHotPlugDeviceGuid,
303 NULL,
304 This->DriverBindingHandle,
305 Controller,
306 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
307 );
308 if (EFI_ERROR (Status)) {
309 TerminalUpdateConsoleDevVariable (L"ConInDev", ParentDevicePath);
310 TerminalUpdateConsoleDevVariable ((L"ConOutDev", ParentDevicePath);
311 TerminalUpdateConsoleDevVariable (L"ErrOutDev", ParentDevicePath);
312 }
313 }
314 }
315 //
316 // Make sure a child handle does not already exist. This driver can only
317 // produce one child per serial port.
318 //
319 Status = gBS->OpenProtocolInformation (
320 Controller,
321 &gEfiSerialIoProtocolGuid,
322 &OpenInfoBuffer,
323 &EntryCount
324 );
325 if (!EFI_ERROR (Status)) {
326 Status = EFI_SUCCESS;
327 for (Index = 0; Index < EntryCount; Index++) {
328 if (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
329 Status = EFI_ALREADY_STARTED;
330 }
331 }
332
333 FreePool (OpenInfoBuffer);
334 if (EFI_ERROR (Status)) {
335 return Status;
336 }
337 }
338 //
339 // If RemainingDevicePath is NULL, then create default device path node
340 //
341 if (RemainingDevicePath == NULL) {
342 DefaultNode = AllocateZeroPool (sizeof (VENDOR_DEVICE_PATH));
343 if (DefaultNode == NULL) {
344 Status = EFI_OUT_OF_RESOURCES;
345 goto Error;
346 }
347
348 TerminalType = FixedPcdGet8 (PcdDefaultTerminalType);
349 // must be between PcAnsiType (0) and VTUTF8Type (3)
350 ASSERT (TerminalType <= VTUTF8Type);
351
352 CopyMem (&DefaultNode->Guid, gTerminalType[TerminalType], sizeof (EFI_GUID));
353 RemainingDevicePath = (EFI_DEVICE_PATH_PROTOCOL*)DefaultNode;
354 } else {
355 //
356 // Use the RemainingDevicePath to determine the terminal type
357 //
358 Node = (VENDOR_DEVICE_PATH *)RemainingDevicePath;
359 if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) {
360 TerminalType = PcAnsiType;
361 } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) {
362 TerminalType = VT100Type;
363 } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) {
364 TerminalType = VT100PlusType;
365 } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {
366 TerminalType = VTUTF8Type;
367 } else {
368 goto Error;
369 }
370 }
371
372 //
373 // Initialize the Terminal Dev
374 //
375 TerminalDevice = AllocateCopyPool (sizeof (TERMINAL_DEV), &gTerminalDevTemplate);
376 if (TerminalDevice == NULL) {
377 Status = EFI_OUT_OF_RESOURCES;
378 goto Error;
379 }
380
381 TerminalDevice->TerminalType = TerminalType;
382 TerminalDevice->SerialIo = SerialIo;
383
384 Status = gBS->CreateEvent (
385 EVT_NOTIFY_WAIT,
386 TPL_NOTIFY,
387 TerminalConInWaitForKey,
388 &TerminalDevice->SimpleInput,
389 &TerminalDevice->SimpleInput.WaitForKey
390 );
391 if (EFI_ERROR (Status)) {
392 goto Error;
393 }
394
395 //
396 // initialize the FIFO buffer used for accommodating
397 // the pre-read pending characters
398 //
399 InitializeRawFiFo (TerminalDevice);
400 InitializeUnicodeFiFo (TerminalDevice);
401 InitializeEfiKeyFiFo (TerminalDevice);
402
403 //
404 // Set the timeout value of serial buffer for
405 // keystroke response performance issue
406 //
407 Mode = TerminalDevice->SerialIo->Mode;
408 SerialInTimeOut = 0;
409 if (Mode->BaudRate != 0) {
410 SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate;
411 }
412
413 Status = TerminalDevice->SerialIo->SetAttributes (
414 TerminalDevice->SerialIo,
415 Mode->BaudRate,
416 Mode->ReceiveFifoDepth,
417 (UINT32) SerialInTimeOut,
418 (EFI_PARITY_TYPE) (Mode->Parity),
419 (UINT8) Mode->DataBits,
420 (EFI_STOP_BITS_TYPE) (Mode->StopBits)
421 );
422 if (EFI_ERROR (Status)) {
423 //
424 // if set attributes operation fails, invalidate
425 // the value of SerialInTimeOut,thus make it
426 // inconsistent with the default timeout value
427 // of serial buffer. This will invoke the recalculation
428 // in the readkeystroke routine.
429 //
430 TerminalDevice->SerialInTimeOut = 0;
431 } else {
432 TerminalDevice->SerialInTimeOut = SerialInTimeOut;
433 }
434 //
435 // Build the device path for the child device
436 //
437 Status = SetTerminalDevicePath (
438 TerminalDevice->TerminalType,
439 ParentDevicePath,
440 &TerminalDevice->DevicePath
441 );
442 if (EFI_ERROR (Status)) {
443 goto Error;
444 }
445
446 DevicePath = TerminalDevice->DevicePath;
447
448 Status = TerminalDevice->SimpleInput.Reset (
449 &TerminalDevice->SimpleInput,
450 FALSE
451 );
452 if (EFI_ERROR (Status)) {
453 //
454 // Need to report Error Code first
455 //
456 goto ReportError;
457 }
458 //
459 // Simple Text Output Protocol
460 //
461 TerminalDevice->SimpleTextOutput.Mode = &TerminalDevice->SimpleTextOutputMode;
462
463 Status = TerminalDevice->SimpleTextOutput.Reset (
464 &TerminalDevice->SimpleTextOutput,
465 FALSE
466 );
467 if (EFI_ERROR (Status)) {
468 goto ReportError;
469 }
470
471 Status = TerminalDevice->SimpleTextOutput.SetMode (
472 &TerminalDevice->SimpleTextOutput,
473 0
474 );
475 if (EFI_ERROR (Status)) {
476 goto ReportError;
477 }
478
479 Status = TerminalDevice->SimpleTextOutput.EnableCursor (
480 &TerminalDevice->SimpleTextOutput,
481 TRUE
482 );
483 if (EFI_ERROR (Status)) {
484 goto ReportError;
485 }
486
487 Status = gBS->CreateEvent (
488 EVT_TIMER,
489 TPL_CALLBACK,
490 NULL,
491 NULL,
492 &TerminalDevice->TwoSecondTimeOut
493 );
494
495 //
496 // Build the component name for the child device
497 //
498 TerminalDevice->ControllerNameTable = NULL;
499 switch (TerminalDevice->TerminalType) {
500 case PcAnsiType:
501 AddUnicodeString (
502 "eng",
503 gTerminalComponentName.SupportedLanguages,
504 &TerminalDevice->ControllerNameTable,
505 (CHAR16 *)L"PC-ANSI Serial Console"
506 );
507 break;
508
509 case VT100Type:
510 AddUnicodeString (
511 "eng",
512 gTerminalComponentName.SupportedLanguages,
513 &TerminalDevice->ControllerNameTable,
514 (CHAR16 *)L"VT-100 Serial Console"
515 );
516 break;
517
518 case VT100PlusType:
519 AddUnicodeString (
520 "eng",
521 gTerminalComponentName.SupportedLanguages,
522 &TerminalDevice->ControllerNameTable,
523 (CHAR16 *)L"VT-100+ Serial Console"
524 );
525 break;
526
527 case VTUTF8Type:
528 AddUnicodeString (
529 "eng",
530 gTerminalComponentName.SupportedLanguages,
531 &TerminalDevice->ControllerNameTable,
532 (CHAR16 *)L"VT-UTF8 Serial Console"
533 );
534 break;
535 }
536 //
537 // Install protocol interfaces for the serial device.
538 //
539 Status = gBS->InstallMultipleProtocolInterfaces (
540 &TerminalDevice->Handle,
541 &gEfiDevicePathProtocolGuid,
542 TerminalDevice->DevicePath,
543 &gEfiSimpleTextInProtocolGuid,
544 &TerminalDevice->SimpleInput,
545 &gEfiSimpleTextOutProtocolGuid,
546 &TerminalDevice->SimpleTextOutput,
547 NULL
548 );
549 if (EFI_ERROR (Status)) {
550 goto Error;
551 }
552 //
553 // if the serial device is a hot plug device, attaches the HotPlugGuid
554 // onto the terminal device handle.
555 //
556 Status = gBS->OpenProtocol (
557 Controller,
558 &gEfiHotPlugDeviceGuid,
559 NULL,
560 This->DriverBindingHandle,
561 Controller,
562 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
563 );
564 if (!EFI_ERROR (Status)) {
565 Status = gBS->InstallMultipleProtocolInterfaces (
566 &TerminalDevice->Handle,
567 &gEfiHotPlugDeviceGuid,
568 NULL,
569 NULL
570 );
571 }
572 //
573 // Register the Parent-Child relationship via
574 // EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
575 //
576 Status = gBS->OpenProtocol (
577 Controller,
578 &gEfiSerialIoProtocolGuid,
579 (VOID **) &TerminalDevice->SerialIo,
580 This->DriverBindingHandle,
581 TerminalDevice->Handle,
582 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
583 );
584 if (EFI_ERROR (Status)) {
585 goto Error;
586 }
587
588 if (DefaultNode != NULL) {
589 FreePool (DefaultNode);
590 }
591
592 return EFI_SUCCESS;
593
594 ReportError:
595 //
596 // Report error code before exiting
597 //
598 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
599 EFI_ERROR_CODE | EFI_ERROR_MINOR,
600 PcdGet32 (PcdStatusCodeValueRemoteConsoleError),
601 DevicePath
602 );
603
604 Error:
605 //
606 // Use the Stop() function to free all resources allocated in Start()
607 //
608 if (TerminalDevice != NULL) {
609
610 if (TerminalDevice->Handle != NULL) {
611 This->Stop (This, Controller, 1, &TerminalDevice->Handle);
612 } else {
613
614 if (TerminalDevice->TwoSecondTimeOut != NULL) {
615 gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);
616 }
617
618 if (TerminalDevice->SimpleInput.WaitForKey != NULL) {
619 gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);
620 }
621
622 if (TerminalDevice->ControllerNameTable != NULL) {
623 FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
624 }
625
626 if (TerminalDevice->DevicePath != NULL) {
627 FreePool (TerminalDevice->DevicePath);
628 }
629
630 FreePool (TerminalDevice);
631 }
632 }
633
634 if (DefaultNode != NULL) {
635 FreePool (DefaultNode);
636 }
637
638 This->Stop (This, Controller, 0, NULL);
639
640 return Status;
641 }
642
643 EFI_STATUS
644 EFIAPI
645 TerminalDriverBindingStop (
646 IN EFI_DRIVER_BINDING_PROTOCOL *This,
647 IN EFI_HANDLE Controller,
648 IN UINTN NumberOfChildren,
649 IN EFI_HANDLE *ChildHandleBuffer
650 )
651 /*++
652
653 Routine Description:
654
655 Stop a device controller.
656
657 Arguments:
658
659 This - A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
660 Controller - A handle to the device being stopped.
661 NumberOfChildren - The number of child device handles in ChildHandleBuffer.
662 ChildHandleBuffer - An array of child handles to be freed.
663
664 Returns:
665
666 EFI_SUCCESS - Operation successful.
667 EFI_DEVICE_ERROR - Devices error.
668
669 --*/
670 {
671 EFI_STATUS Status;
672 UINTN Index;
673 BOOLEAN AllChildrenStopped;
674 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;
675 TERMINAL_DEV *TerminalDevice;
676 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
677 EFI_SERIAL_IO_PROTOCOL *SerialIo;
678 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
679
680 Status = gBS->HandleProtocol (
681 Controller,
682 &gEfiDevicePathProtocolGuid,
683 (VOID **) &DevicePath
684 );
685 if (EFI_ERROR (Status)) {
686 return Status;
687 }
688
689 //
690 // Complete all outstanding transactions to Controller.
691 // Don't allow any new transaction to Controller to be started.
692 //
693 if (NumberOfChildren == 0) {
694 //
695 // Close the bus driver
696 //
697 Status = gBS->OpenProtocol (
698 Controller,
699 &gEfiCallerIdGuid,
700 (VOID **) &ParentDevicePath,
701 This->DriverBindingHandle,
702 Controller,
703 EFI_OPEN_PROTOCOL_GET_PROTOCOL
704 );
705 if (!EFI_ERROR (Status)) {
706 //
707 // Remove Parent Device Path from
708 // the Console Device Environment Variables
709 //
710 TerminalRemoveConsoleDevVariable (L"ConInDev", ParentDevicePath);
711 TerminalRemoveConsoleDevVariable (L"ConOutDev", ParentDevicePath);
712 TerminalRemoveConsoleDevVariable (L"ErrOutDev", ParentDevicePath);
713
714 //
715 // Uninstall the Terminal Driver's GUID Tag from the Serial controller
716 //
717 Status = gBS->UninstallMultipleProtocolInterfaces (
718 Controller,
719 &gEfiCallerIdGuid,
720 ParentDevicePath,
721 NULL
722 );
723
724 //
725 // Free the ParentDevicePath that was duplicated in Start()
726 //
727 if (!EFI_ERROR (Status)) {
728 FreePool (ParentDevicePath);
729 }
730 }
731
732 gBS->CloseProtocol (
733 Controller,
734 &gEfiSerialIoProtocolGuid,
735 This->DriverBindingHandle,
736 Controller
737 );
738
739 gBS->CloseProtocol (
740 Controller,
741 &gEfiDevicePathProtocolGuid,
742 This->DriverBindingHandle,
743 Controller
744 );
745
746 return EFI_SUCCESS;
747 }
748
749 AllChildrenStopped = TRUE;
750
751 for (Index = 0; Index < NumberOfChildren; Index++) {
752
753 Status = gBS->OpenProtocol (
754 ChildHandleBuffer[Index],
755 &gEfiSimpleTextOutProtocolGuid,
756 (VOID **) &SimpleTextOutput,
757 This->DriverBindingHandle,
758 ChildHandleBuffer[Index],
759 EFI_OPEN_PROTOCOL_GET_PROTOCOL
760 );
761 if (!EFI_ERROR (Status)) {
762
763 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);
764
765 gBS->CloseProtocol (
766 Controller,
767 &gEfiSerialIoProtocolGuid,
768 This->DriverBindingHandle,
769 ChildHandleBuffer[Index]
770 );
771
772 Status = gBS->UninstallMultipleProtocolInterfaces (
773 ChildHandleBuffer[Index],
774 &gEfiSimpleTextInProtocolGuid,
775 &TerminalDevice->SimpleInput,
776 &gEfiSimpleTextOutProtocolGuid,
777 &TerminalDevice->SimpleTextOutput,
778 &gEfiDevicePathProtocolGuid,
779 TerminalDevice->DevicePath,
780 NULL
781 );
782 if (EFI_ERROR (Status)) {
783 gBS->OpenProtocol (
784 Controller,
785 &gEfiSerialIoProtocolGuid,
786 (VOID **) &SerialIo,
787 This->DriverBindingHandle,
788 ChildHandleBuffer[Index],
789 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
790 );
791 } else {
792
793 if (TerminalDevice->ControllerNameTable != NULL) {
794 FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
795 }
796
797 Status = gBS->OpenProtocol (
798 ChildHandleBuffer[Index],
799 &gEfiHotPlugDeviceGuid,
800 NULL,
801 This->DriverBindingHandle,
802 Controller,
803 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
804 );
805 if (!EFI_ERROR (Status)) {
806 Status = gBS->UninstallMultipleProtocolInterfaces (
807 ChildHandleBuffer[Index],
808 &gEfiHotPlugDeviceGuid,
809 NULL,
810 NULL
811 );
812 } else {
813 Status = EFI_SUCCESS;
814 }
815
816 gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);
817 gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);
818 FreePool (TerminalDevice->DevicePath);
819 FreePool (TerminalDevice);
820 }
821 }
822
823 if (EFI_ERROR (Status)) {
824 AllChildrenStopped = FALSE;
825 }
826 }
827
828 if (!AllChildrenStopped) {
829 return EFI_DEVICE_ERROR;
830 }
831
832 return EFI_SUCCESS;
833 }
834
835 VOID
836 TerminalUpdateConsoleDevVariable (
837 IN CHAR16 *VariableName,
838 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
839 )
840 {
841 EFI_STATUS Status;
842 UINTN VariableSize;
843 UINT8 TerminalType;
844 EFI_DEVICE_PATH_PROTOCOL *Variable;
845 EFI_DEVICE_PATH_PROTOCOL *NewVariable;
846 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
847
848 Variable = NULL;
849
850 //
851 // Get global variable and its size according to the name given.
852 //
853 Variable = TerminalGetVariableAndSize (
854 VariableName,
855 &gEfiGlobalVariableGuid,
856 &VariableSize
857 );
858 //
859 // Append terminal device path onto the variable.
860 //
861 for (TerminalType = PcAnsiType; TerminalType <= VTUTF8Type; TerminalType++) {
862 SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);
863 NewVariable = AppendDevicePathInstance (Variable, TempDevicePath);
864 if (Variable != NULL) {
865 FreePool (Variable);
866 }
867
868 if (TempDevicePath != NULL) {
869 FreePool (TempDevicePath);
870 }
871
872 Variable = NewVariable;
873 }
874
875 VariableSize = GetDevicePathSize (Variable);
876
877 Status = gRT->SetVariable (
878 VariableName,
879 &gEfiGlobalVariableGuid,
880 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
881 VariableSize,
882 Variable
883 );
884 ASSERT_EFI_ERROR (Status);
885 FreePool (Variable);
886
887 return ;
888 }
889
890 VOID
891 TerminalRemoveConsoleDevVariable (
892 IN CHAR16 *VariableName,
893 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
894 )
895 /*++
896
897 Routine Description:
898
899 Remove console device variable.
900
901 Arguments:
902
903 VariableName - A pointer to the variable name.
904 ParentDevicePath - A pointer to the parent device path.
905
906 Returns:
907
908 --*/
909 {
910 EFI_STATUS Status;
911 BOOLEAN FoundOne;
912 BOOLEAN Match;
913 UINTN VariableSize;
914 UINTN InstanceSize;
915 UINT8 TerminalType;
916 EFI_DEVICE_PATH_PROTOCOL *Instance;
917 EFI_DEVICE_PATH_PROTOCOL *Variable;
918 EFI_DEVICE_PATH_PROTOCOL *OriginalVariable;
919 EFI_DEVICE_PATH_PROTOCOL *NewVariable;
920 EFI_DEVICE_PATH_PROTOCOL *SavedNewVariable;
921 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
922
923 Variable = NULL;
924 Instance = NULL;
925
926 //
927 // Get global variable and its size according to the name given.
928 //
929 Variable = TerminalGetVariableAndSize (
930 VariableName,
931 &gEfiGlobalVariableGuid,
932 &VariableSize
933 );
934 if (Variable == NULL) {
935 return ;
936 }
937
938 FoundOne = FALSE;
939 OriginalVariable = Variable;
940 NewVariable = NULL;
941
942 //
943 // Get first device path instance from Variable
944 //
945 Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);
946 if (Instance == NULL) {
947 FreePool (OriginalVariable);
948 return ;
949 }
950 //
951 // Loop through all the device path instances of Variable
952 //
953 do {
954 //
955 // Loop through all the terminal types that this driver supports
956 //
957 Match = FALSE;
958 for (TerminalType = PcAnsiType; TerminalType <= VTUTF8Type; TerminalType++) {
959
960 SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);
961
962 //
963 // Compare the genterated device path to the current device path instance
964 //
965 if (TempDevicePath != NULL) {
966 if (CompareMem (Instance, TempDevicePath, InstanceSize) == 0) {
967 Match = TRUE;
968 FoundOne = TRUE;
969 }
970
971 FreePool (TempDevicePath);
972 }
973 }
974 //
975 // If a match was not found, then keep the current device path instance
976 //
977 if (!Match) {
978 SavedNewVariable = NewVariable;
979 NewVariable = AppendDevicePathInstance (NewVariable, Instance);
980 if (SavedNewVariable != NULL) {
981 FreePool (SavedNewVariable);
982 }
983 }
984 //
985 // Get next device path instance from Variable
986 //
987 FreePool (Instance);
988 Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);
989 } while (Instance != NULL);
990
991 FreePool (OriginalVariable);
992
993 if (FoundOne) {
994 VariableSize = GetDevicePathSize (NewVariable);
995
996 Status = gRT->SetVariable (
997 VariableName,
998 &gEfiGlobalVariableGuid,
999 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
1000 VariableSize,
1001 NewVariable
1002 );
1003 ASSERT_EFI_ERROR (Status);
1004 }
1005
1006 if (NewVariable != NULL) {
1007 FreePool (NewVariable);
1008 }
1009
1010 return ;
1011 }
1012
1013 VOID *
1014 TerminalGetVariableAndSize (
1015 IN CHAR16 *Name,
1016 IN EFI_GUID *VendorGuid,
1017 OUT UINTN *VariableSize
1018 )
1019 /*++
1020
1021 Routine Description:
1022 Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
1023 buffer, and the size of the buffer. On failure return NULL.
1024
1025 Arguments:
1026 Name - String part of EFI variable name
1027
1028 VendorGuid - GUID part of EFI variable name
1029
1030 VariableSize - Returns the size of the EFI variable that was read
1031
1032 Returns:
1033 Dynamically allocated memory that contains a copy of the EFI variable.
1034 Caller is repsoncible freeing the buffer.
1035
1036 NULL - Variable was not read
1037
1038 --*/
1039 {
1040 EFI_STATUS Status;
1041 UINTN BufferSize;
1042 VOID *Buffer;
1043
1044 Buffer = NULL;
1045
1046 //
1047 // Pass in a small size buffer to find the actual variable size.
1048 //
1049 BufferSize = 1;
1050 Buffer = AllocatePool (BufferSize);
1051 if (Buffer == NULL) {
1052 *VariableSize = 0;
1053 return NULL;
1054 }
1055
1056 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
1057
1058 if (Status == EFI_SUCCESS) {
1059 *VariableSize = BufferSize;
1060 return Buffer;
1061
1062 } else if (Status == EFI_BUFFER_TOO_SMALL) {
1063 //
1064 // Allocate the buffer to return
1065 //
1066 FreePool (Buffer);
1067 Buffer = AllocatePool (BufferSize);
1068 if (Buffer == NULL) {
1069 *VariableSize = 0;
1070 return NULL;
1071 }
1072 //
1073 // Read variable into the allocated buffer.
1074 //
1075 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
1076 if (EFI_ERROR (Status)) {
1077 BufferSize = 0;
1078 FreePool (Buffer);
1079 Buffer = NULL;
1080 }
1081 } else {
1082 //
1083 // Variable not found or other errors met.
1084 //
1085 BufferSize = 0;
1086 FreePool (Buffer);
1087 Buffer = NULL;
1088 }
1089
1090 *VariableSize = BufferSize;
1091 return Buffer;
1092 }
1093
1094 EFI_STATUS
1095 SetTerminalDevicePath (
1096 IN UINT8 TerminalType,
1097 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
1098 OUT EFI_DEVICE_PATH_PROTOCOL **TerminalDevicePath
1099 )
1100 {
1101 VENDOR_DEVICE_PATH Node;
1102
1103 *TerminalDevicePath = NULL;
1104 Node.Header.Type = MESSAGING_DEVICE_PATH;
1105 Node.Header.SubType = MSG_VENDOR_DP;
1106
1107 //
1108 // generate terminal device path node according to terminal type.
1109 //
1110 switch (TerminalType) {
1111
1112 case PcAnsiType:
1113 CopyMem (
1114 &Node.Guid,
1115 &gEfiPcAnsiGuid,
1116 sizeof (EFI_GUID)
1117 );
1118 break;
1119
1120 case VT100Type:
1121 CopyMem (
1122 &Node.Guid,
1123 &gEfiVT100Guid,
1124 sizeof (EFI_GUID)
1125 );
1126 break;
1127
1128 case VT100PlusType:
1129 CopyMem (
1130 &Node.Guid,
1131 &gEfiVT100PlusGuid,
1132 sizeof (EFI_GUID)
1133 );
1134 break;
1135
1136 case VTUTF8Type:
1137 CopyMem (
1138 &Node.Guid,
1139 &gEfiVTUTF8Guid,
1140 sizeof (EFI_GUID)
1141 );
1142 break;
1143
1144 default:
1145 return EFI_UNSUPPORTED;
1146 break;
1147 }
1148
1149 SetDevicePathNodeLength (
1150 &Node.Header,
1151 sizeof (VENDOR_DEVICE_PATH)
1152 );
1153 //
1154 // append the terminal node onto parent device path
1155 // to generate a complete terminal device path.
1156 //
1157 *TerminalDevicePath = AppendDevicePathNode (
1158 ParentDevicePath,
1159 (EFI_DEVICE_PATH_PROTOCOL *) &Node
1160 );
1161 if (*TerminalDevicePath == NULL) {
1162 return EFI_OUT_OF_RESOURCES;
1163 }
1164
1165 return EFI_SUCCESS;
1166 }
1167
1168 VOID
1169 InitializeRawFiFo (
1170 IN TERMINAL_DEV *TerminalDevice
1171 )
1172 {
1173 //
1174 // Make the raw fifo empty.
1175 //
1176 TerminalDevice->RawFiFo.Head = TerminalDevice->RawFiFo.Tail;
1177 }
1178
1179 VOID
1180 InitializeUnicodeFiFo (
1181 IN TERMINAL_DEV *TerminalDevice
1182 )
1183 {
1184 //
1185 // Make the unicode fifo empty
1186 //
1187 TerminalDevice->UnicodeFiFo.Head = TerminalDevice->UnicodeFiFo.Tail;
1188 }
1189
1190 VOID
1191 InitializeEfiKeyFiFo (
1192 IN TERMINAL_DEV *TerminalDevice
1193 )
1194 {
1195 //
1196 // Make the efi key fifo empty
1197 //
1198 TerminalDevice->EfiKeyFiFo.Head = TerminalDevice->EfiKeyFiFo.Tail;
1199 }
1200
1201
1202 /**
1203 The user Entry Point for module Terminal. The user code starts with this function.
1204
1205 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1206 @param[in] SystemTable A pointer to the EFI System Table.
1207
1208 @retval EFI_SUCCESS The entry point is executed successfully.
1209 @retval other Some error occurs when executing this entry point.
1210
1211 **/
1212 EFI_STATUS
1213 EFIAPI
1214 InitializeTerminal(
1215 IN EFI_HANDLE ImageHandle,
1216 IN EFI_SYSTEM_TABLE *SystemTable
1217 )
1218 {
1219 EFI_STATUS Status;
1220
1221 //
1222 // Install driver model protocol(s).
1223 //
1224 Status = EfiLibInstallAllDriverProtocols (
1225 ImageHandle,
1226 SystemTable,
1227 &gTerminalDriverBinding,
1228 ImageHandle,
1229 &gTerminalComponentName,
1230 NULL,
1231 NULL
1232 );
1233 ASSERT_EFI_ERROR (Status);
1234
1235
1236 return Status;
1237 }