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