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