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