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