]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Universal/Console/Terminal/Dxe/Terminal.c
c7c1bdda8f8faf78c1e746e39c8d2ddf5a18b910
[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 0x10,
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 Mode->Parity,
406 (UINT8) Mode->DataBits,
407 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 gBS->FreePool (Variable);
901
902 return ;
903 }
904
905 VOID
906 TerminalRemoveConsoleDevVariable (
907 IN CHAR16 *VariableName,
908 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
909 )
910 /*++
911
912 Routine Description:
913
914 Remove console device variable.
915
916 Arguments:
917
918 VariableName - A pointer to the variable name.
919 ParentDevicePath - A pointer to the parent device path.
920
921 Returns:
922
923 --*/
924 {
925 EFI_STATUS Status;
926 BOOLEAN FoundOne;
927 BOOLEAN Match;
928 UINTN VariableSize;
929 UINTN InstanceSize;
930 UINT8 TerminalType;
931 EFI_DEVICE_PATH_PROTOCOL *Instance;
932 EFI_DEVICE_PATH_PROTOCOL *Variable;
933 EFI_DEVICE_PATH_PROTOCOL *OriginalVariable;
934 EFI_DEVICE_PATH_PROTOCOL *NewVariable;
935 EFI_DEVICE_PATH_PROTOCOL *SavedNewVariable;
936 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
937
938 Variable = NULL;
939 Instance = NULL;
940
941 //
942 // Get global variable and its size according to the name given.
943 //
944 Variable = TerminalGetVariableAndSize (
945 VariableName,
946 &gEfiGlobalVariableGuid,
947 &VariableSize
948 );
949 if (Variable == NULL) {
950 return ;
951 }
952
953 FoundOne = FALSE;
954 OriginalVariable = Variable;
955 NewVariable = NULL;
956
957 //
958 // Get first device path instance from Variable
959 //
960 Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);
961 if (Instance == NULL) {
962 gBS->FreePool (OriginalVariable);
963 return ;
964 }
965 //
966 // Loop through all the device path instances of Variable
967 //
968 do {
969 //
970 // Loop through all the terminal types that this driver supports
971 //
972 Match = FALSE;
973 for (TerminalType = PcAnsiType; TerminalType <= VTUTF8Type; TerminalType++) {
974
975 SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);
976
977 //
978 // Compare the genterated device path to the current device path instance
979 //
980 if (TempDevicePath != NULL) {
981 if (CompareMem (Instance, TempDevicePath, InstanceSize) == 0) {
982 Match = TRUE;
983 FoundOne = TRUE;
984 }
985
986 gBS->FreePool (TempDevicePath);
987 }
988 }
989 //
990 // If a match was not found, then keep the current device path instance
991 //
992 if (!Match) {
993 SavedNewVariable = NewVariable;
994 NewVariable = AppendDevicePathInstance (NewVariable, Instance);
995 if (SavedNewVariable != NULL) {
996 gBS->FreePool (SavedNewVariable);
997 }
998 }
999 //
1000 // Get next device path instance from Variable
1001 //
1002 gBS->FreePool (Instance);
1003 Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);
1004 } while (Instance != NULL);
1005
1006 gBS->FreePool (OriginalVariable);
1007
1008 if (FoundOne) {
1009 VariableSize = GetDevicePathSize (NewVariable);
1010
1011 Status = gRT->SetVariable (
1012 VariableName,
1013 &gEfiGlobalVariableGuid,
1014 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
1015 VariableSize,
1016 NewVariable
1017 );
1018 }
1019
1020 if (NewVariable != NULL) {
1021 gBS->FreePool (NewVariable);
1022 }
1023
1024 return ;
1025 }
1026
1027 VOID *
1028 TerminalGetVariableAndSize (
1029 IN CHAR16 *Name,
1030 IN EFI_GUID *VendorGuid,
1031 OUT UINTN *VariableSize
1032 )
1033 /*++
1034
1035 Routine Description:
1036 Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
1037 buffer, and the size of the buffer. On failure return NULL.
1038
1039 Arguments:
1040 Name - String part of EFI variable name
1041
1042 VendorGuid - GUID part of EFI variable name
1043
1044 VariableSize - Returns the size of the EFI variable that was read
1045
1046 Returns:
1047 Dynamically allocated memory that contains a copy of the EFI variable.
1048 Caller is repsoncible freeing the buffer.
1049
1050 NULL - Variable was not read
1051
1052 --*/
1053 {
1054 EFI_STATUS Status;
1055 UINTN BufferSize;
1056 VOID *Buffer;
1057
1058 Buffer = NULL;
1059
1060 //
1061 // Pass in a small size buffer to find the actual variable size.
1062 //
1063 BufferSize = 1;
1064 Buffer = AllocatePool (BufferSize);
1065 if (Buffer == NULL) {
1066 *VariableSize = 0;
1067 return NULL;
1068 }
1069
1070 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
1071
1072 if (Status == EFI_SUCCESS) {
1073 *VariableSize = BufferSize;
1074 return Buffer;
1075
1076 } else if (Status == EFI_BUFFER_TOO_SMALL) {
1077 //
1078 // Allocate the buffer to return
1079 //
1080 gBS->FreePool (Buffer);
1081 Buffer = AllocatePool (BufferSize);
1082 if (Buffer == NULL) {
1083 *VariableSize = 0;
1084 return NULL;
1085 }
1086 //
1087 // Read variable into the allocated buffer.
1088 //
1089 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
1090 if (EFI_ERROR (Status)) {
1091 BufferSize = 0;
1092 gBS->FreePool (Buffer);
1093 Buffer = NULL;
1094 }
1095 } else {
1096 //
1097 // Variable not found or other errors met.
1098 //
1099 BufferSize = 0;
1100 gBS->FreePool (Buffer);
1101 Buffer = NULL;
1102 }
1103
1104 *VariableSize = BufferSize;
1105 return Buffer;
1106 }
1107
1108 EFI_STATUS
1109 SetTerminalDevicePath (
1110 IN UINT8 TerminalType,
1111 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
1112 OUT EFI_DEVICE_PATH_PROTOCOL **TerminalDevicePath
1113 )
1114 {
1115 VENDOR_DEVICE_PATH Node;
1116
1117 *TerminalDevicePath = NULL;
1118 Node.Header.Type = MESSAGING_DEVICE_PATH;
1119 Node.Header.SubType = MSG_VENDOR_DP;
1120
1121 //
1122 // generate terminal device path node according to terminal type.
1123 //
1124 switch (TerminalType) {
1125
1126 case PcAnsiType:
1127 CopyMem (
1128 &Node.Guid,
1129 &gEfiPcAnsiGuid,
1130 sizeof (EFI_GUID)
1131 );
1132 break;
1133
1134 case VT100Type:
1135 CopyMem (
1136 &Node.Guid,
1137 &gEfiVT100Guid,
1138 sizeof (EFI_GUID)
1139 );
1140 break;
1141
1142 case VT100PlusType:
1143 CopyMem (
1144 &Node.Guid,
1145 &gEfiVT100PlusGuid,
1146 sizeof (EFI_GUID)
1147 );
1148 break;
1149
1150 case VTUTF8Type:
1151 CopyMem (
1152 &Node.Guid,
1153 &gEfiVTUTF8Guid,
1154 sizeof (EFI_GUID)
1155 );
1156 break;
1157
1158 default:
1159 return EFI_UNSUPPORTED;
1160 break;
1161 }
1162
1163 SetDevicePathNodeLength (
1164 &Node.Header,
1165 sizeof (VENDOR_DEVICE_PATH)
1166 );
1167 //
1168 // append the terminal node onto parent device path
1169 // to generate a complete terminal device path.
1170 //
1171 *TerminalDevicePath = AppendDevicePathNode (
1172 ParentDevicePath,
1173 (EFI_DEVICE_PATH_PROTOCOL *) &Node
1174 );
1175 if (*TerminalDevicePath == NULL) {
1176 return EFI_OUT_OF_RESOURCES;
1177 }
1178
1179 return EFI_SUCCESS;
1180 }
1181
1182 VOID
1183 InitializeRawFiFo (
1184 IN TERMINAL_DEV *TerminalDevice
1185 )
1186 {
1187 //
1188 // Make the raw fifo empty.
1189 //
1190 TerminalDevice->RawFiFo.Head = TerminalDevice->RawFiFo.Tail;
1191 }
1192
1193 VOID
1194 InitializeUnicodeFiFo (
1195 IN TERMINAL_DEV *TerminalDevice
1196 )
1197 {
1198 //
1199 // Make the unicode fifo empty
1200 //
1201 TerminalDevice->UnicodeFiFo.Head = TerminalDevice->UnicodeFiFo.Tail;
1202 }
1203
1204 VOID
1205 InitializeEfiKeyFiFo (
1206 IN TERMINAL_DEV *TerminalDevice
1207 )
1208 {
1209 //
1210 // Make the efi key fifo empty
1211 //
1212 TerminalDevice->EfiKeyFiFo.Head = TerminalDevice->EfiKeyFiFo.Tail;
1213 }