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