]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
MdeModulePkg/Universal: Fix typos in comments
[mirror_edk2.git] / MdeModulePkg / Universal / Console / TerminalDxe / Terminal.c
1 /** @file
2 Produces Simple Text Input Protocol, Simple Text Input Extended Protocol and
3 Simple Text Output Protocol upon Serial IO Protocol.
4
5 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16
17 #include "Terminal.h"
18
19 //
20 // Globals
21 //
22 EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding = {
23 TerminalDriverBindingSupported,
24 TerminalDriverBindingStart,
25 TerminalDriverBindingStop,
26 0xa,
27 NULL,
28 NULL
29 };
30
31
32 EFI_GUID *gTerminalType[] = {
33 &gEfiPcAnsiGuid,
34 &gEfiVT100Guid,
35 &gEfiVT100PlusGuid,
36 &gEfiVTUTF8Guid,
37 &gEfiTtyTermGuid
38 };
39
40
41 TERMINAL_DEV mTerminalDevTemplate = {
42 TERMINAL_DEV_SIGNATURE,
43 NULL,
44 0,
45 NULL,
46 NULL,
47 { // SimpleTextInput
48 TerminalConInReset,
49 TerminalConInReadKeyStroke,
50 NULL
51 },
52 { // SimpleTextOutput
53 TerminalConOutReset,
54 TerminalConOutOutputString,
55 TerminalConOutTestString,
56 TerminalConOutQueryMode,
57 TerminalConOutSetMode,
58 TerminalConOutSetAttribute,
59 TerminalConOutClearScreen,
60 TerminalConOutSetCursorPosition,
61 TerminalConOutEnableCursor,
62 NULL
63 },
64 { // SimpleTextOutputMode
65 1, // MaxMode
66 0, // Mode
67 EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK), // Attribute
68 0, // CursorColumn
69 0, // CursorRow
70 TRUE // CursorVisible
71 },
72 NULL, // TerminalConsoleModeData
73 0, // SerialInTimeOut
74
75 NULL, // RawFifo
76 NULL, // UnicodeFiFo
77 NULL, // EfiKeyFiFo
78
79 NULL, // ControllerNameTable
80 NULL, // TimerEvent
81 NULL, // TwoSecondTimeOut
82 INPUT_STATE_DEFAULT,
83 RESET_STATE_DEFAULT,
84 {
85 0,
86 0,
87 0
88 },
89 0,
90 FALSE,
91 { // SimpleTextInputEx
92 TerminalConInResetEx,
93 TerminalConInReadKeyStrokeEx,
94 NULL,
95 TerminalConInSetState,
96 TerminalConInRegisterKeyNotify,
97 TerminalConInUnregisterKeyNotify,
98 },
99 { // NotifyList
100 NULL,
101 NULL,
102 }
103 };
104
105 TERMINAL_CONSOLE_MODE_DATA mTerminalConsoleModeData[] = {
106 {100, 31},
107 //
108 // New modes can be added here.
109 //
110 };
111
112 /**
113 Test to see if this driver supports Controller.
114
115 @param This Protocol instance pointer.
116 @param Controller Handle of device to test
117 @param RemainingDevicePath Optional parameter use to pick a specific child
118 device to start.
119
120 @retval EFI_SUCCESS This driver supports this device.
121 @retval EFI_ALREADY_STARTED This driver is already running on this device.
122 @retval other This driver does not support this device.
123
124 **/
125 EFI_STATUS
126 EFIAPI
127 TerminalDriverBindingSupported (
128 IN EFI_DRIVER_BINDING_PROTOCOL *This,
129 IN EFI_HANDLE Controller,
130 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
131 )
132 {
133 EFI_STATUS Status;
134 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
135 EFI_SERIAL_IO_PROTOCOL *SerialIo;
136 VENDOR_DEVICE_PATH *Node;
137
138 //
139 // If remaining device path is not NULL, then make sure it is a
140 // device path that describes a terminal communications protocol.
141 //
142 if (RemainingDevicePath != NULL) {
143 //
144 // Check if RemainingDevicePath is the End of Device Path Node,
145 // if yes, go on checking other conditions
146 //
147 if (!IsDevicePathEnd (RemainingDevicePath)) {
148 //
149 // If RemainingDevicePath isn't the End of Device Path Node,
150 // check its validation
151 //
152 Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;
153
154 if (Node->Header.Type != MESSAGING_DEVICE_PATH ||
155 Node->Header.SubType != MSG_VENDOR_DP ||
156 DevicePathNodeLength(&Node->Header) != sizeof(VENDOR_DEVICE_PATH)) {
157
158 return EFI_UNSUPPORTED;
159
160 }
161 //
162 // only supports PC ANSI, VT100, VT100+, VT-UTF8, and TtyTerm terminal types
163 //
164 if (!CompareGuid (&Node->Guid, &gEfiPcAnsiGuid) &&
165 !CompareGuid (&Node->Guid, &gEfiVT100Guid) &&
166 !CompareGuid (&Node->Guid, &gEfiVT100PlusGuid) &&
167 !CompareGuid (&Node->Guid, &gEfiVTUTF8Guid) &&
168 !CompareGuid (&Node->Guid, &gEfiTtyTermGuid)) {
169
170 return EFI_UNSUPPORTED;
171 }
172 }
173 }
174 //
175 // Open the IO Abstraction(s) needed to perform the supported test
176 // The Controller must support the Serial I/O Protocol.
177 // This driver is a bus driver with at most 1 child device, so it is
178 // ok for it to be already started.
179 //
180 Status = gBS->OpenProtocol (
181 Controller,
182 &gEfiSerialIoProtocolGuid,
183 (VOID **) &SerialIo,
184 This->DriverBindingHandle,
185 Controller,
186 EFI_OPEN_PROTOCOL_BY_DRIVER
187 );
188 if (Status == EFI_ALREADY_STARTED) {
189 return EFI_SUCCESS;
190 }
191
192 if (EFI_ERROR (Status)) {
193 return Status;
194 }
195
196 //
197 // Close the I/O Abstraction(s) used to perform the supported test
198 //
199 gBS->CloseProtocol (
200 Controller,
201 &gEfiSerialIoProtocolGuid,
202 This->DriverBindingHandle,
203 Controller
204 );
205
206 //
207 // Open the EFI Device Path protocol needed to perform the supported test
208 //
209 Status = gBS->OpenProtocol (
210 Controller,
211 &gEfiDevicePathProtocolGuid,
212 (VOID **) &ParentDevicePath,
213 This->DriverBindingHandle,
214 Controller,
215 EFI_OPEN_PROTOCOL_BY_DRIVER
216 );
217 if (Status == EFI_ALREADY_STARTED) {
218 return EFI_SUCCESS;
219 }
220
221 if (EFI_ERROR (Status)) {
222 return Status;
223 }
224
225 //
226 // Close protocol, don't use device path protocol in the Support() function
227 //
228 gBS->CloseProtocol (
229 Controller,
230 &gEfiDevicePathProtocolGuid,
231 This->DriverBindingHandle,
232 Controller
233 );
234
235 return Status;
236 }
237
238 /**
239 Build the terminal device path for the child device according to the
240 terminal type.
241
242 @param ParentDevicePath Parent device path.
243 @param RemainingDevicePath A specific child device.
244
245 @return The child device path built.
246
247 **/
248 EFI_DEVICE_PATH_PROTOCOL*
249 EFIAPI
250 BuildTerminalDevpath (
251 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
252 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
253 )
254 {
255 EFI_DEVICE_PATH_PROTOCOL *TerminalDevicePath;
256 UINT8 TerminalType;
257 VENDOR_DEVICE_PATH *Node;
258 EFI_STATUS Status;
259
260 TerminalDevicePath = NULL;
261
262 //
263 // Use the RemainingDevicePath to determine the terminal type
264 //
265 Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;
266 if (Node == NULL) {
267 TerminalType = PcdGet8 (PcdDefaultTerminalType);
268
269 } else if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) {
270
271 TerminalType = PCANSITYPE;
272
273 } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) {
274
275 TerminalType = VT100TYPE;
276
277 } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) {
278
279 TerminalType = VT100PLUSTYPE;
280
281 } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {
282
283 TerminalType = VTUTF8TYPE;
284
285 } else if (CompareGuid (&Node->Guid, &gEfiTtyTermGuid)) {
286
287 TerminalType = TTYTERMTYPE;
288
289 } else {
290 return NULL;
291 }
292
293 //
294 // Build the device path for the child device
295 //
296 Status = SetTerminalDevicePath (
297 TerminalType,
298 ParentDevicePath,
299 &TerminalDevicePath
300 );
301 if (EFI_ERROR (Status)) {
302 return NULL;
303 }
304 return TerminalDevicePath;
305 }
306
307 /**
308 Compare a device path data structure to that of all the nodes of a
309 second device path instance.
310
311 @param Multi A pointer to a multi-instance device path data structure.
312 @param Single A pointer to a single-instance device path data structure.
313
314 @retval TRUE If the Single is contained within Multi.
315 @retval FALSE The Single is not match within Multi.
316
317 **/
318 BOOLEAN
319 MatchDevicePaths (
320 IN EFI_DEVICE_PATH_PROTOCOL *Multi,
321 IN EFI_DEVICE_PATH_PROTOCOL *Single
322 )
323 {
324 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
325 EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
326 UINTN Size;
327
328 DevicePath = Multi;
329 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
330 //
331 // Search for the match of 'Single' in 'Multi'
332 //
333 while (DevicePathInst != NULL) {
334 //
335 // If the single device path is found in multiple device paths,
336 // return success
337 //
338 if (CompareMem (Single, DevicePathInst, Size) == 0) {
339 FreePool (DevicePathInst);
340 return TRUE;
341 }
342
343 FreePool (DevicePathInst);
344 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
345 }
346
347 return FALSE;
348 }
349
350 /**
351 Check whether the terminal device path is in the global variable.
352
353 @param VariableName Pointer to one global variable.
354 @param TerminalDevicePath Pointer to the terminal device's device path.
355
356 @retval TRUE The devcie is in the global variable.
357 @retval FALSE The devcie is not in the global variable.
358
359 **/
360 BOOLEAN
361 IsTerminalInConsoleVariable (
362 IN CHAR16 *VariableName,
363 IN EFI_DEVICE_PATH_PROTOCOL *TerminalDevicePath
364 )
365 {
366 EFI_DEVICE_PATH_PROTOCOL *Variable;
367 BOOLEAN ReturnFlag;
368
369 //
370 // Get global variable and its size according to the name given.
371 //
372 GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);
373 if (Variable == NULL) {
374 return FALSE;
375 }
376
377 //
378 // Check whether the terminal device path is one of the variable instances.
379 //
380 ReturnFlag = MatchDevicePaths (Variable, TerminalDevicePath);
381
382 FreePool (Variable);
383
384 return ReturnFlag;
385 }
386
387 /**
388 Free notify functions list.
389
390 @param ListHead The list head
391
392 @retval EFI_SUCCESS Free the notify list successfully.
393 @retval EFI_INVALID_PARAMETER ListHead is NULL.
394
395 **/
396 EFI_STATUS
397 TerminalFreeNotifyList (
398 IN OUT LIST_ENTRY *ListHead
399 )
400 {
401 TERMINAL_CONSOLE_IN_EX_NOTIFY *NotifyNode;
402
403 if (ListHead == NULL) {
404 return EFI_INVALID_PARAMETER;
405 }
406 while (!IsListEmpty (ListHead)) {
407 NotifyNode = CR (
408 ListHead->ForwardLink,
409 TERMINAL_CONSOLE_IN_EX_NOTIFY,
410 NotifyEntry,
411 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
412 );
413 RemoveEntryList (ListHead->ForwardLink);
414 FreePool (NotifyNode);
415 }
416
417 return EFI_SUCCESS;
418 }
419
420 /**
421 Initialize all the text modes which the terminal console supports.
422
423 It returns information for available text modes that the terminal can support.
424
425 @param[out] TextModeCount The total number of text modes that terminal console supports.
426 @param[out] TextModeData The buffer to the text modes column and row information.
427 Caller is responsible to free it when it's non-NULL.
428
429 @retval EFI_SUCCESS The supporting mode information is returned.
430 @retval EFI_INVALID_PARAMETER The parameters are invalid.
431
432 **/
433 EFI_STATUS
434 InitializeTerminalConsoleTextMode (
435 OUT UINTN *TextModeCount,
436 OUT TERMINAL_CONSOLE_MODE_DATA **TextModeData
437 )
438 {
439 UINTN Index;
440 UINTN Count;
441 TERMINAL_CONSOLE_MODE_DATA *ModeBuffer;
442 TERMINAL_CONSOLE_MODE_DATA *NewModeBuffer;
443 UINTN ValidCount;
444 UINTN ValidIndex;
445
446 if ((TextModeCount == NULL) || (TextModeData == NULL)) {
447 return EFI_INVALID_PARAMETER;
448 }
449
450 Count = sizeof (mTerminalConsoleModeData) / sizeof (TERMINAL_CONSOLE_MODE_DATA);
451
452 //
453 // Get defined mode buffer pointer.
454 //
455 ModeBuffer = mTerminalConsoleModeData;
456
457 //
458 // Here we make sure that the final mode exposed does not include the duplicated modes,
459 // and does not include the invalid modes which exceed the max column and row.
460 // Reserve 2 modes for 80x25, 80x50 of terminal console.
461 //
462 NewModeBuffer = AllocateZeroPool (sizeof (TERMINAL_CONSOLE_MODE_DATA) * (Count + 2));
463 ASSERT (NewModeBuffer != NULL);
464
465 //
466 // Mode 0 and mode 1 is for 80x25, 80x50 according to UEFI spec.
467 //
468 ValidCount = 0;
469
470 NewModeBuffer[ValidCount].Columns = 80;
471 NewModeBuffer[ValidCount].Rows = 25;
472 ValidCount++;
473
474 NewModeBuffer[ValidCount].Columns = 80;
475 NewModeBuffer[ValidCount].Rows = 50;
476 ValidCount++;
477
478 //
479 // Start from mode 2 to put the valid mode other than 80x25 and 80x50 in the output mode buffer.
480 //
481 for (Index = 0; Index < Count; Index++) {
482 if ((ModeBuffer[Index].Columns == 0) || (ModeBuffer[Index].Rows == 0)) {
483 //
484 // Skip the pre-defined mode which is invalid.
485 //
486 continue;
487 }
488 for (ValidIndex = 0; ValidIndex < ValidCount; ValidIndex++) {
489 if ((ModeBuffer[Index].Columns == NewModeBuffer[ValidIndex].Columns) &&
490 (ModeBuffer[Index].Rows == NewModeBuffer[ValidIndex].Rows)) {
491 //
492 // Skip the duplicated mode.
493 //
494 break;
495 }
496 }
497 if (ValidIndex == ValidCount) {
498 NewModeBuffer[ValidCount].Columns = ModeBuffer[Index].Columns;
499 NewModeBuffer[ValidCount].Rows = ModeBuffer[Index].Rows;
500 ValidCount++;
501 }
502 }
503
504 DEBUG_CODE (
505 for (Index = 0; Index < ValidCount; Index++) {
506 DEBUG ((EFI_D_INFO, "Terminal - Mode %d, Column = %d, Row = %d\n",
507 Index, NewModeBuffer[Index].Columns, NewModeBuffer[Index].Rows));
508 }
509 );
510
511 //
512 // Return valid mode count and mode information buffer.
513 //
514 *TextModeCount = ValidCount;
515 *TextModeData = NewModeBuffer;
516 return EFI_SUCCESS;
517 }
518
519 /**
520 Start this driver on Controller by opening a Serial IO protocol,
521 reading Device Path, and creating a child handle with a Simple Text In,
522 Simple Text In Ex and Simple Text Out protocol, and device path protocol.
523 And store Console Device Environment Variables.
524
525 @param This Protocol instance pointer.
526 @param Controller Handle of device to bind driver to
527 @param RemainingDevicePath Optional parameter use to pick a specific child
528 device to start.
529
530 @retval EFI_SUCCESS This driver is added to Controller.
531 @retval EFI_ALREADY_STARTED This driver is already running on Controller.
532 @retval other This driver does not support this device.
533
534 **/
535 EFI_STATUS
536 EFIAPI
537 TerminalDriverBindingStart (
538 IN EFI_DRIVER_BINDING_PROTOCOL *This,
539 IN EFI_HANDLE Controller,
540 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
541 )
542 {
543 EFI_STATUS Status;
544 EFI_SERIAL_IO_PROTOCOL *SerialIo;
545 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
546 VENDOR_DEVICE_PATH *Node;
547 EFI_SERIAL_IO_MODE *Mode;
548 UINTN SerialInTimeOut;
549 TERMINAL_DEV *TerminalDevice;
550 UINT8 TerminalType;
551 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
552 UINTN EntryCount;
553 UINTN Index;
554 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
555 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;
556 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextInput;
557 BOOLEAN ConInSelected;
558 BOOLEAN ConOutSelected;
559 BOOLEAN NullRemaining;
560 BOOLEAN SimTxtInInstalled;
561 BOOLEAN SimTxtOutInstalled;
562 BOOLEAN FirstEnter;
563 UINTN ModeCount;
564
565 TerminalDevice = NULL;
566 ConInSelected = FALSE;
567 ConOutSelected = FALSE;
568 NullRemaining = FALSE;
569 SimTxtInInstalled = FALSE;
570 SimTxtOutInstalled = FALSE;
571 FirstEnter = FALSE;
572 //
573 // Get the Device Path Protocol to build the device path of the child device
574 //
575 Status = gBS->OpenProtocol (
576 Controller,
577 &gEfiDevicePathProtocolGuid,
578 (VOID **) &ParentDevicePath,
579 This->DriverBindingHandle,
580 Controller,
581 EFI_OPEN_PROTOCOL_BY_DRIVER
582 );
583 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
584 return Status;
585 }
586
587 //
588 // Open the Serial I/O Protocol BY_DRIVER. It might already be started.
589 //
590 Status = gBS->OpenProtocol (
591 Controller,
592 &gEfiSerialIoProtocolGuid,
593 (VOID **) &SerialIo,
594 This->DriverBindingHandle,
595 Controller,
596 EFI_OPEN_PROTOCOL_BY_DRIVER
597 );
598 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
599 return Status;
600 }
601
602 if (Status != EFI_ALREADY_STARTED) {
603 //
604 // the serial I/O protocol never be opened before, it is the first
605 // time to start the serial Io controller
606 //
607 FirstEnter = TRUE;
608 }
609
610 //
611 // Serial I/O is not already open by this driver, then tag the handle
612 // with the Terminal Driver GUID and update the ConInDev, ConOutDev, and
613 // StdErrDev variables with the list of possible terminal types on this
614 // serial port.
615 //
616 Status = gBS->OpenProtocol (
617 Controller,
618 &gEfiCallerIdGuid,
619 NULL,
620 This->DriverBindingHandle,
621 Controller,
622 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
623 );
624 if (EFI_ERROR (Status)) {
625 Status = gBS->InstallMultipleProtocolInterfaces (
626 &Controller,
627 &gEfiCallerIdGuid,
628 DuplicateDevicePath (ParentDevicePath),
629 NULL
630 );
631 if (EFI_ERROR (Status)) {
632 goto Error;
633 }
634
635 if (!IsHotPlugDevice (ParentDevicePath)) {
636 //
637 // if the serial device is a hot plug device, do not update the
638 // ConInDev, ConOutDev, and StdErrDev variables.
639 //
640 TerminalUpdateConsoleDevVariable (L"ConInDev", ParentDevicePath);
641 TerminalUpdateConsoleDevVariable (L"ConOutDev", ParentDevicePath);
642 TerminalUpdateConsoleDevVariable (L"ErrOutDev", ParentDevicePath);
643 }
644 }
645
646 //
647 // Check the requirement for the SimpleTxtIn and SimpleTxtOut protocols
648 //
649 // Simple In/Out Protocol will not be installed onto the handle if the
650 // device path to the handle is not present in the ConIn/ConOut
651 // environment variable. But If RemainingDevicePath is NULL, then always
652 // produce both Simple In and Simple Text Output Protocols. This is required
653 // for the connect all sequences to make sure all possible consoles are
654 // produced no matter what the current values of ConIn, ConOut, or StdErr are.
655 //
656 if (RemainingDevicePath == NULL) {
657 NullRemaining = TRUE;
658 }
659
660 DevicePath = BuildTerminalDevpath (ParentDevicePath, RemainingDevicePath);
661 if (DevicePath != NULL) {
662 ConInSelected = IsTerminalInConsoleVariable (L"ConIn", DevicePath);
663 ConOutSelected = IsTerminalInConsoleVariable (L"ConOut", DevicePath);
664 FreePool (DevicePath);
665 } else {
666 goto Error;
667 }
668 //
669 // Not create the child terminal handle if both Simple In/In Ex and
670 // Simple text Out protocols are not required to be published
671 //
672 if ((!ConInSelected)&&(!ConOutSelected)&&(!NullRemaining)) {
673 goto Error;
674 }
675
676 //
677 // create the child terminal handle during first entry
678 //
679 if (FirstEnter) {
680 //
681 // First enther the start function
682 //
683 FirstEnter = FALSE;
684 //
685 // Make sure a child handle does not already exist. This driver can only
686 // produce one child per serial port.
687 //
688 Status = gBS->OpenProtocolInformation (
689 Controller,
690 &gEfiSerialIoProtocolGuid,
691 &OpenInfoBuffer,
692 &EntryCount
693 );
694 if (!EFI_ERROR (Status)) {
695 Status = EFI_SUCCESS;
696 for (Index = 0; Index < EntryCount; Index++) {
697 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
698 Status = EFI_ALREADY_STARTED;
699 }
700 }
701
702 FreePool (OpenInfoBuffer);
703 if (EFI_ERROR (Status)) {
704 goto Error;
705 }
706 }
707
708 //
709 // If RemainingDevicePath is NULL, use default terminal type
710 //
711 if (RemainingDevicePath == NULL) {
712 TerminalType = PcdGet8 (PcdDefaultTerminalType);
713 //
714 // Must be between PCANSITYPE (0) and TTYTERMTYPE (4)
715 //
716 ASSERT (TerminalType <= TTYTERMTYPE);
717 } else if (!IsDevicePathEnd (RemainingDevicePath)) {
718 //
719 // If RemainingDevicePath isn't the End of Device Path Node,
720 // Use the RemainingDevicePath to determine the terminal type
721 //
722 Node = (VENDOR_DEVICE_PATH *)RemainingDevicePath;
723 if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) {
724 TerminalType = PCANSITYPE;
725 } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) {
726 TerminalType = VT100TYPE;
727 } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) {
728 TerminalType = VT100PLUSTYPE;
729 } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {
730 TerminalType = VTUTF8TYPE;
731 } else if (CompareGuid (&Node->Guid, &gEfiTtyTermGuid)) {
732 TerminalType = TTYTERMTYPE;
733 } else {
734 goto Error;
735 }
736 } else {
737 //
738 // If RemainingDevicePath is the End of Device Path Node,
739 // skip enumerate any device and return EFI_SUCESSS
740 //
741 return EFI_SUCCESS;
742 }
743
744 //
745 // Initialize the Terminal Dev
746 //
747 TerminalDevice = AllocateCopyPool (sizeof (TERMINAL_DEV), &mTerminalDevTemplate);
748 if (TerminalDevice == NULL) {
749 Status = EFI_OUT_OF_RESOURCES;
750 goto Error;
751 }
752
753 TerminalDevice->TerminalType = TerminalType;
754 TerminalDevice->SerialIo = SerialIo;
755
756 InitializeListHead (&TerminalDevice->NotifyList);
757 Status = gBS->CreateEvent (
758 EVT_NOTIFY_WAIT,
759 TPL_NOTIFY,
760 TerminalConInWaitForKeyEx,
761 TerminalDevice,
762 &TerminalDevice->SimpleInputEx.WaitForKeyEx
763 );
764 if (EFI_ERROR (Status)) {
765 goto Error;
766 }
767
768 Status = gBS->CreateEvent (
769 EVT_NOTIFY_WAIT,
770 TPL_NOTIFY,
771 TerminalConInWaitForKey,
772 TerminalDevice,
773 &TerminalDevice->SimpleInput.WaitForKey
774 );
775 if (EFI_ERROR (Status)) {
776 goto Error;
777 }
778 //
779 // Allocates and initializes the FIFO buffer to be zero, used for accommodating
780 // the pre-read pending characters.
781 //
782 TerminalDevice->RawFiFo = AllocateZeroPool (sizeof (RAW_DATA_FIFO));
783 if (TerminalDevice->RawFiFo == NULL) {
784 goto Error;
785 }
786 TerminalDevice->UnicodeFiFo = AllocateZeroPool (sizeof (UNICODE_FIFO));
787 if (TerminalDevice->UnicodeFiFo == NULL) {
788 goto Error;
789 }
790 TerminalDevice->EfiKeyFiFo = AllocateZeroPool (sizeof (EFI_KEY_FIFO));
791 if (TerminalDevice->EfiKeyFiFo == NULL) {
792 goto Error;
793 }
794
795 //
796 // Set the timeout value of serial buffer for
797 // keystroke response performance issue
798 //
799 Mode = TerminalDevice->SerialIo->Mode;
800
801 SerialInTimeOut = 0;
802 if (Mode->BaudRate != 0) {
803 SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate;
804 }
805
806 Status = TerminalDevice->SerialIo->SetAttributes (
807 TerminalDevice->SerialIo,
808 Mode->BaudRate,
809 Mode->ReceiveFifoDepth,
810 (UINT32) SerialInTimeOut,
811 (EFI_PARITY_TYPE) (Mode->Parity),
812 (UINT8) Mode->DataBits,
813 (EFI_STOP_BITS_TYPE) (Mode->StopBits)
814 );
815 if (EFI_ERROR (Status)) {
816 //
817 // if set attributes operation fails, invalidate
818 // the value of SerialInTimeOut,thus make it
819 // inconsistent with the default timeout value
820 // of serial buffer. This will invoke the recalculation
821 // in the readkeystroke routine.
822 //
823 TerminalDevice->SerialInTimeOut = 0;
824 } else {
825 TerminalDevice->SerialInTimeOut = SerialInTimeOut;
826 }
827 //
828 // Set Simple Text Output Protocol from template.
829 //
830 SimpleTextOutput = CopyMem (
831 &TerminalDevice->SimpleTextOutput,
832 &mTerminalDevTemplate.SimpleTextOutput,
833 sizeof (mTerminalDevTemplate.SimpleTextOutput)
834 );
835 SimpleTextOutput->Mode = &TerminalDevice->SimpleTextOutputMode;
836
837 Status = InitializeTerminalConsoleTextMode (&ModeCount, &TerminalDevice->TerminalConsoleModeData);
838 if (EFI_ERROR (Status)) {
839 goto ReportError;
840 }
841 TerminalDevice->SimpleTextOutputMode.MaxMode = (INT32) ModeCount;
842
843 //
844 // For terminal devices, cursor is always visible
845 //
846 TerminalDevice->SimpleTextOutputMode.CursorVisible = TRUE;
847 Status = TerminalConOutSetAttribute (
848 SimpleTextOutput,
849 EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)
850 );
851 if (EFI_ERROR (Status)) {
852 goto ReportError;
853 }
854
855 //
856 // Build the component name for the child device
857 //
858 TerminalDevice->ControllerNameTable = NULL;
859 switch (TerminalDevice->TerminalType) {
860 case PCANSITYPE:
861 AddUnicodeString2 (
862 "eng",
863 gTerminalComponentName.SupportedLanguages,
864 &TerminalDevice->ControllerNameTable,
865 (CHAR16 *)L"PC-ANSI Serial Console",
866 TRUE
867 );
868 AddUnicodeString2 (
869 "en",
870 gTerminalComponentName2.SupportedLanguages,
871 &TerminalDevice->ControllerNameTable,
872 (CHAR16 *)L"PC-ANSI Serial Console",
873 FALSE
874 );
875
876 break;
877
878 case VT100TYPE:
879 AddUnicodeString2 (
880 "eng",
881 gTerminalComponentName.SupportedLanguages,
882 &TerminalDevice->ControllerNameTable,
883 (CHAR16 *)L"VT-100 Serial Console",
884 TRUE
885 );
886 AddUnicodeString2 (
887 "en",
888 gTerminalComponentName2.SupportedLanguages,
889 &TerminalDevice->ControllerNameTable,
890 (CHAR16 *)L"VT-100 Serial Console",
891 FALSE
892 );
893
894 break;
895
896 case VT100PLUSTYPE:
897 AddUnicodeString2 (
898 "eng",
899 gTerminalComponentName.SupportedLanguages,
900 &TerminalDevice->ControllerNameTable,
901 (CHAR16 *)L"VT-100+ Serial Console",
902 TRUE
903 );
904 AddUnicodeString2 (
905 "en",
906 gTerminalComponentName2.SupportedLanguages,
907 &TerminalDevice->ControllerNameTable,
908 (CHAR16 *)L"VT-100+ Serial Console",
909 FALSE
910 );
911
912 break;
913
914 case VTUTF8TYPE:
915 AddUnicodeString2 (
916 "eng",
917 gTerminalComponentName.SupportedLanguages,
918 &TerminalDevice->ControllerNameTable,
919 (CHAR16 *)L"VT-UTF8 Serial Console",
920 TRUE
921 );
922 AddUnicodeString2 (
923 "en",
924 gTerminalComponentName2.SupportedLanguages,
925 &TerminalDevice->ControllerNameTable,
926 (CHAR16 *)L"VT-UTF8 Serial Console",
927 FALSE
928 );
929
930 break;
931
932 case TTYTERMTYPE:
933 AddUnicodeString2 (
934 "eng",
935 gTerminalComponentName.SupportedLanguages,
936 &TerminalDevice->ControllerNameTable,
937 (CHAR16 *)L"Tty Terminal Serial Console",
938 TRUE
939 );
940 AddUnicodeString2 (
941 "en",
942 gTerminalComponentName2.SupportedLanguages,
943 &TerminalDevice->ControllerNameTable,
944 (CHAR16 *)L"Tty Terminal Serial Console",
945 FALSE
946 );
947
948 break;
949 }
950
951 //
952 // Build the device path for the child device
953 //
954 Status = SetTerminalDevicePath (
955 TerminalDevice->TerminalType,
956 ParentDevicePath,
957 &TerminalDevice->DevicePath
958 );
959 if (EFI_ERROR (Status)) {
960 goto Error;
961 }
962
963 Status = TerminalConOutReset (SimpleTextOutput, FALSE);
964 if (EFI_ERROR (Status)) {
965 goto ReportError;
966 }
967
968 Status = TerminalConOutSetMode (SimpleTextOutput, 0);
969 if (EFI_ERROR (Status)) {
970 goto ReportError;
971 }
972
973 Status = TerminalConOutEnableCursor (SimpleTextOutput, TRUE);
974 if (EFI_ERROR (Status)) {
975 goto ReportError;
976 }
977
978 Status = gBS->CreateEvent (
979 EVT_TIMER | EVT_NOTIFY_SIGNAL,
980 TPL_NOTIFY,
981 TerminalConInTimerHandler,
982 TerminalDevice,
983 &TerminalDevice->TimerEvent
984 );
985 ASSERT_EFI_ERROR (Status);
986
987 Status = gBS->SetTimer (
988 TerminalDevice->TimerEvent,
989 TimerPeriodic,
990 KEYBOARD_TIMER_INTERVAL
991 );
992 ASSERT_EFI_ERROR (Status);
993
994 Status = gBS->CreateEvent (
995 EVT_TIMER,
996 TPL_CALLBACK,
997 NULL,
998 NULL,
999 &TerminalDevice->TwoSecondTimeOut
1000 );
1001 ASSERT_EFI_ERROR (Status);
1002
1003 Status = gBS->InstallProtocolInterface (
1004 &TerminalDevice->Handle,
1005 &gEfiDevicePathProtocolGuid,
1006 EFI_NATIVE_INTERFACE,
1007 TerminalDevice->DevicePath
1008 );
1009 if (EFI_ERROR (Status)) {
1010 goto Error;
1011 }
1012
1013 //
1014 // Register the Parent-Child relationship via
1015 // EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
1016 //
1017 Status = gBS->OpenProtocol (
1018 Controller,
1019 &gEfiSerialIoProtocolGuid,
1020 (VOID **) &TerminalDevice->SerialIo,
1021 This->DriverBindingHandle,
1022 TerminalDevice->Handle,
1023 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1024 );
1025 if (EFI_ERROR (Status)) {
1026 goto Error;
1027 }
1028 }
1029
1030 //
1031 // Find the child handle, and get its TerminalDevice private data
1032 //
1033 Status = gBS->OpenProtocolInformation (
1034 Controller,
1035 &gEfiSerialIoProtocolGuid,
1036 &OpenInfoBuffer,
1037 &EntryCount
1038 );
1039 if (!EFI_ERROR (Status)) {
1040 Status = EFI_NOT_FOUND;
1041 ASSERT (OpenInfoBuffer != NULL);
1042 for (Index = 0; Index < EntryCount; Index++) {
1043 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
1044 //
1045 // Find the child terminal handle.
1046 // Test whether the SimpleTxtIn and SimpleTxtOut have been published
1047 //
1048 Status = gBS->OpenProtocol (
1049 OpenInfoBuffer[Index].ControllerHandle,
1050 &gEfiSimpleTextInProtocolGuid,
1051 (VOID **) &SimpleTextInput,
1052 This->DriverBindingHandle,
1053 OpenInfoBuffer[Index].ControllerHandle,
1054 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1055 );
1056 if (!EFI_ERROR (Status)) {
1057 SimTxtInInstalled = TRUE;
1058 TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (SimpleTextInput);
1059 }
1060
1061 Status = gBS->OpenProtocol (
1062 OpenInfoBuffer[Index].ControllerHandle,
1063 &gEfiSimpleTextOutProtocolGuid,
1064 (VOID **) &SimpleTextOutput,
1065 This->DriverBindingHandle,
1066 OpenInfoBuffer[Index].ControllerHandle,
1067 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1068 );
1069 if (!EFI_ERROR (Status)) {
1070 SimTxtOutInstalled = TRUE;
1071 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);
1072 }
1073 Status = EFI_SUCCESS;
1074 break;
1075 }
1076 }
1077
1078 FreePool (OpenInfoBuffer);
1079 if (EFI_ERROR (Status)) {
1080 goto ReportError;
1081 }
1082 } else {
1083 goto ReportError;
1084 }
1085
1086 ASSERT (TerminalDevice != NULL);
1087 //
1088 // Only do the reset if the device path is in the Conout variable
1089 //
1090 if (ConInSelected && !SimTxtInInstalled) {
1091 Status = TerminalDevice->SimpleInput.Reset (
1092 &TerminalDevice->SimpleInput,
1093 FALSE
1094 );
1095 if (EFI_ERROR (Status)) {
1096 //
1097 // Need to report Error Code first
1098 //
1099 goto ReportError;
1100 }
1101 }
1102
1103 //
1104 // Only output the configure string to remote terminal if the device path
1105 // is in the Conout variable
1106 //
1107 if (ConOutSelected && !SimTxtOutInstalled) {
1108 Status = TerminalDevice->SimpleTextOutput.SetAttribute (
1109 &TerminalDevice->SimpleTextOutput,
1110 EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)
1111 );
1112 if (EFI_ERROR (Status)) {
1113 goto ReportError;
1114 }
1115
1116 Status = TerminalDevice->SimpleTextOutput.Reset (
1117 &TerminalDevice->SimpleTextOutput,
1118 FALSE
1119 );
1120 if (EFI_ERROR (Status)) {
1121 goto ReportError;
1122 }
1123
1124 Status = TerminalDevice->SimpleTextOutput.SetMode (
1125 &TerminalDevice->SimpleTextOutput,
1126 0
1127 );
1128 if (EFI_ERROR (Status)) {
1129 goto ReportError;
1130 }
1131
1132 Status = TerminalDevice->SimpleTextOutput.EnableCursor (
1133 &TerminalDevice->SimpleTextOutput,
1134 TRUE
1135 );
1136 if (EFI_ERROR (Status)) {
1137 goto ReportError;
1138 }
1139 }
1140
1141 //
1142 // Simple In/Out Protocol will not be installed onto the handle if the
1143 // device path to the handle is not present in the ConIn/ConOut
1144 // environment variable. But If RemainingDevicePath is NULL, then always
1145 // produce both Simple In and Simple Text Output Protocols. This is required
1146 // for the connect all sequences to make sure all possible consoles are
1147 // produced no matter what the current values of ConIn, ConOut, or StdErr are.
1148 //
1149 if (!SimTxtInInstalled && (ConInSelected || NullRemaining)) {
1150 Status = gBS->InstallMultipleProtocolInterfaces (
1151 &TerminalDevice->Handle,
1152 &gEfiSimpleTextInProtocolGuid,
1153 &TerminalDevice->SimpleInput,
1154 &gEfiSimpleTextInputExProtocolGuid,
1155 &TerminalDevice->SimpleInputEx,
1156 NULL
1157 );
1158 if (EFI_ERROR (Status)) {
1159 goto Error;
1160 }
1161 }
1162
1163 if (!SimTxtOutInstalled && (ConOutSelected || NullRemaining)) {
1164 Status = gBS->InstallProtocolInterface (
1165 &TerminalDevice->Handle,
1166 &gEfiSimpleTextOutProtocolGuid,
1167 EFI_NATIVE_INTERFACE,
1168 &TerminalDevice->SimpleTextOutput
1169 );
1170 if (EFI_ERROR (Status)) {
1171 goto Error;
1172 }
1173 }
1174
1175 return EFI_SUCCESS;
1176
1177 ReportError:
1178 //
1179 // Report error code before exiting
1180 //
1181 DevicePath = ParentDevicePath;
1182 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1183 EFI_ERROR_CODE | EFI_ERROR_MINOR,
1184 (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),
1185 DevicePath
1186 );
1187
1188 Error:
1189 //
1190 // Use the Stop() function to free all resources allocated in Start()
1191 //
1192 if (TerminalDevice != NULL) {
1193
1194 if (TerminalDevice->Handle != NULL) {
1195 This->Stop (This, Controller, 1, &TerminalDevice->Handle);
1196 } else {
1197
1198 if (TerminalDevice->TwoSecondTimeOut != NULL) {
1199 gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);
1200 }
1201
1202 if (TerminalDevice->TimerEvent != NULL) {
1203 gBS->CloseEvent (TerminalDevice->TimerEvent);
1204 }
1205
1206 if (TerminalDevice->SimpleInput.WaitForKey != NULL) {
1207 gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);
1208 }
1209
1210 if (TerminalDevice->SimpleInputEx.WaitForKeyEx != NULL) {
1211 gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);
1212 }
1213
1214 TerminalFreeNotifyList (&TerminalDevice->NotifyList);
1215
1216 if (TerminalDevice->RawFiFo != NULL) {
1217 FreePool (TerminalDevice->RawFiFo);
1218 }
1219 if (TerminalDevice->UnicodeFiFo != NULL) {
1220 FreePool (TerminalDevice->UnicodeFiFo);
1221 }
1222 if (TerminalDevice->EfiKeyFiFo != NULL) {
1223 FreePool (TerminalDevice->EfiKeyFiFo);
1224 }
1225
1226 if (TerminalDevice->ControllerNameTable != NULL) {
1227 FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
1228 }
1229
1230 if (TerminalDevice->DevicePath != NULL) {
1231 FreePool (TerminalDevice->DevicePath);
1232 }
1233
1234 if (TerminalDevice->TerminalConsoleModeData != NULL) {
1235 FreePool (TerminalDevice->TerminalConsoleModeData);
1236 }
1237
1238 FreePool (TerminalDevice);
1239 }
1240 }
1241
1242 This->Stop (This, Controller, 0, NULL);
1243
1244 return Status;
1245 }
1246
1247 /**
1248 Stop this driver on Controller by closing Simple Text In, Simple Text
1249 In Ex, Simple Text Out protocol, and removing parent device path from
1250 Console Device Environment Variables.
1251
1252 @param This Protocol instance pointer.
1253 @param Controller Handle of device to stop driver on
1254 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
1255 children is zero stop the entire bus driver.
1256 @param ChildHandleBuffer List of Child Handles to Stop.
1257
1258 @retval EFI_SUCCESS This driver is removed Controller.
1259 @retval other This driver could not be removed from this device.
1260
1261 **/
1262 EFI_STATUS
1263 EFIAPI
1264 TerminalDriverBindingStop (
1265 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1266 IN EFI_HANDLE Controller,
1267 IN UINTN NumberOfChildren,
1268 IN EFI_HANDLE *ChildHandleBuffer
1269 )
1270 {
1271 EFI_STATUS Status;
1272 UINTN Index;
1273 BOOLEAN AllChildrenStopped;
1274 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;
1275 TERMINAL_DEV *TerminalDevice;
1276 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
1277 EFI_SERIAL_IO_PROTOCOL *SerialIo;
1278 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1279
1280 Status = gBS->HandleProtocol (
1281 Controller,
1282 &gEfiDevicePathProtocolGuid,
1283 (VOID **) &DevicePath
1284 );
1285 if (EFI_ERROR (Status)) {
1286 return Status;
1287 }
1288
1289 //
1290 // Complete all outstanding transactions to Controller.
1291 // Don't allow any new transaction to Controller to be started.
1292 //
1293 if (NumberOfChildren == 0) {
1294 //
1295 // Close the bus driver
1296 //
1297 Status = gBS->OpenProtocol (
1298 Controller,
1299 &gEfiCallerIdGuid,
1300 (VOID **) &ParentDevicePath,
1301 This->DriverBindingHandle,
1302 Controller,
1303 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1304 );
1305 if (!EFI_ERROR (Status)) {
1306 //
1307 // Remove Parent Device Path from
1308 // the Console Device Environment Variables
1309 //
1310 TerminalRemoveConsoleDevVariable (L"ConInDev", ParentDevicePath);
1311 TerminalRemoveConsoleDevVariable (L"ConOutDev", ParentDevicePath);
1312 TerminalRemoveConsoleDevVariable (L"ErrOutDev", ParentDevicePath);
1313
1314 //
1315 // Uninstall the Terminal Driver's GUID Tag from the Serial controller
1316 //
1317 Status = gBS->UninstallMultipleProtocolInterfaces (
1318 Controller,
1319 &gEfiCallerIdGuid,
1320 ParentDevicePath,
1321 NULL
1322 );
1323
1324 //
1325 // Free the ParentDevicePath that was duplicated in Start()
1326 //
1327 if (!EFI_ERROR (Status)) {
1328 FreePool (ParentDevicePath);
1329 }
1330 }
1331
1332 gBS->CloseProtocol (
1333 Controller,
1334 &gEfiSerialIoProtocolGuid,
1335 This->DriverBindingHandle,
1336 Controller
1337 );
1338
1339 gBS->CloseProtocol (
1340 Controller,
1341 &gEfiDevicePathProtocolGuid,
1342 This->DriverBindingHandle,
1343 Controller
1344 );
1345
1346 return EFI_SUCCESS;
1347 }
1348
1349 AllChildrenStopped = TRUE;
1350
1351 for (Index = 0; Index < NumberOfChildren; Index++) {
1352
1353 Status = gBS->OpenProtocol (
1354 ChildHandleBuffer[Index],
1355 &gEfiSimpleTextOutProtocolGuid,
1356 (VOID **) &SimpleTextOutput,
1357 This->DriverBindingHandle,
1358 ChildHandleBuffer[Index],
1359 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1360 );
1361 if (!EFI_ERROR (Status)) {
1362
1363 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);
1364
1365 gBS->CloseProtocol (
1366 Controller,
1367 &gEfiSerialIoProtocolGuid,
1368 This->DriverBindingHandle,
1369 ChildHandleBuffer[Index]
1370 );
1371
1372 Status = gBS->UninstallMultipleProtocolInterfaces (
1373 ChildHandleBuffer[Index],
1374 &gEfiSimpleTextInProtocolGuid,
1375 &TerminalDevice->SimpleInput,
1376 &gEfiSimpleTextInputExProtocolGuid,
1377 &TerminalDevice->SimpleInputEx,
1378 &gEfiSimpleTextOutProtocolGuid,
1379 &TerminalDevice->SimpleTextOutput,
1380 &gEfiDevicePathProtocolGuid,
1381 TerminalDevice->DevicePath,
1382 NULL
1383 );
1384 if (EFI_ERROR (Status)) {
1385 gBS->OpenProtocol (
1386 Controller,
1387 &gEfiSerialIoProtocolGuid,
1388 (VOID **) &SerialIo,
1389 This->DriverBindingHandle,
1390 ChildHandleBuffer[Index],
1391 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1392 );
1393 } else {
1394
1395 if (TerminalDevice->ControllerNameTable != NULL) {
1396 FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
1397 }
1398
1399 gBS->CloseEvent (TerminalDevice->TimerEvent);
1400 gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);
1401 gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);
1402 gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);
1403 TerminalFreeNotifyList (&TerminalDevice->NotifyList);
1404 FreePool (TerminalDevice->DevicePath);
1405 if (TerminalDevice->TerminalConsoleModeData != NULL) {
1406 FreePool (TerminalDevice->TerminalConsoleModeData);
1407 }
1408 FreePool (TerminalDevice);
1409 }
1410 }
1411
1412 if (EFI_ERROR (Status)) {
1413 AllChildrenStopped = FALSE;
1414 }
1415 }
1416
1417 if (!AllChildrenStopped) {
1418 return EFI_DEVICE_ERROR;
1419 }
1420
1421 return EFI_SUCCESS;
1422 }
1423
1424 /**
1425 Update terminal device path in Console Device Environment Variables.
1426
1427 @param VariableName The Console Device Environment Variable.
1428 @param ParentDevicePath The terminal device path to be updated.
1429
1430 **/
1431 VOID
1432 TerminalUpdateConsoleDevVariable (
1433 IN CHAR16 *VariableName,
1434 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
1435 )
1436 {
1437 EFI_STATUS Status;
1438 UINTN NameSize;
1439 UINTN VariableSize;
1440 UINT8 TerminalType;
1441 EFI_DEVICE_PATH_PROTOCOL *Variable;
1442 EFI_DEVICE_PATH_PROTOCOL *NewVariable;
1443 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1444 EDKII_SET_VARIABLE_STATUS *SetVariableStatus;
1445
1446 //
1447 // Get global variable and its size according to the name given.
1448 //
1449 GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);
1450 if (Variable == NULL) {
1451 return;
1452 }
1453
1454 //
1455 // Append terminal device path onto the variable.
1456 //
1457 for (TerminalType = PCANSITYPE; TerminalType <= TTYTERMTYPE; TerminalType++) {
1458 SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);
1459 NewVariable = AppendDevicePathInstance (Variable, TempDevicePath);
1460 ASSERT (NewVariable != NULL);
1461 if (Variable != NULL) {
1462 FreePool (Variable);
1463 }
1464
1465 if (TempDevicePath != NULL) {
1466 FreePool (TempDevicePath);
1467 }
1468
1469 Variable = NewVariable;
1470 }
1471
1472 VariableSize = GetDevicePathSize (Variable);
1473
1474 Status = gRT->SetVariable (
1475 VariableName,
1476 &gEfiGlobalVariableGuid,
1477 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
1478 VariableSize,
1479 Variable
1480 );
1481
1482 if (EFI_ERROR (Status)) {
1483 NameSize = StrSize (VariableName);
1484 SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + VariableSize);
1485 if (SetVariableStatus != NULL) {
1486 CopyGuid (&SetVariableStatus->Guid, &gEfiGlobalVariableGuid);
1487 SetVariableStatus->NameSize = NameSize;
1488 SetVariableStatus->DataSize = VariableSize;
1489 SetVariableStatus->SetStatus = Status;
1490 SetVariableStatus->Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
1491 CopyMem (SetVariableStatus + 1, VariableName, NameSize);
1492 CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Variable, VariableSize);
1493
1494 REPORT_STATUS_CODE_EX (
1495 EFI_ERROR_CODE,
1496 PcdGet32 (PcdErrorCodeSetVariable),
1497 0,
1498 NULL,
1499 &gEdkiiStatusCodeDataTypeVariableGuid,
1500 SetVariableStatus,
1501 sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + VariableSize
1502 );
1503
1504 FreePool (SetVariableStatus);
1505 }
1506 }
1507
1508 FreePool (Variable);
1509
1510 return ;
1511 }
1512
1513
1514 /**
1515 Remove terminal device path from Console Device Environment Variables.
1516
1517 @param VariableName Console Device Environment Variables.
1518 @param ParentDevicePath The terminal device path to be updated.
1519
1520 **/
1521 VOID
1522 TerminalRemoveConsoleDevVariable (
1523 IN CHAR16 *VariableName,
1524 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
1525 )
1526 {
1527 EFI_STATUS Status;
1528 BOOLEAN FoundOne;
1529 BOOLEAN Match;
1530 UINTN VariableSize;
1531 UINTN InstanceSize;
1532 UINT8 TerminalType;
1533 EFI_DEVICE_PATH_PROTOCOL *Instance;
1534 EFI_DEVICE_PATH_PROTOCOL *Variable;
1535 EFI_DEVICE_PATH_PROTOCOL *OriginalVariable;
1536 EFI_DEVICE_PATH_PROTOCOL *NewVariable;
1537 EFI_DEVICE_PATH_PROTOCOL *SavedNewVariable;
1538 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1539
1540 Instance = NULL;
1541
1542 //
1543 // Get global variable and its size according to the name given.
1544 //
1545 GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);
1546 if (Variable == NULL) {
1547 return ;
1548 }
1549
1550 FoundOne = FALSE;
1551 OriginalVariable = Variable;
1552 NewVariable = NULL;
1553
1554 //
1555 // Get first device path instance from Variable
1556 //
1557 Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);
1558 if (Instance == NULL) {
1559 FreePool (OriginalVariable);
1560 return ;
1561 }
1562 //
1563 // Loop through all the device path instances of Variable
1564 //
1565 do {
1566 //
1567 // Loop through all the terminal types that this driver supports
1568 //
1569 Match = FALSE;
1570 for (TerminalType = PCANSITYPE; TerminalType <= TTYTERMTYPE; TerminalType++) {
1571
1572 SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);
1573
1574 //
1575 // Compare the generated device path to the current device path instance
1576 //
1577 if (TempDevicePath != NULL) {
1578 if (CompareMem (Instance, TempDevicePath, InstanceSize) == 0) {
1579 Match = TRUE;
1580 FoundOne = TRUE;
1581 }
1582
1583 FreePool (TempDevicePath);
1584 }
1585 }
1586 //
1587 // If a match was not found, then keep the current device path instance
1588 //
1589 if (!Match) {
1590 SavedNewVariable = NewVariable;
1591 NewVariable = AppendDevicePathInstance (NewVariable, Instance);
1592 if (SavedNewVariable != NULL) {
1593 FreePool (SavedNewVariable);
1594 }
1595 }
1596 //
1597 // Get next device path instance from Variable
1598 //
1599 FreePool (Instance);
1600 Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);
1601 } while (Instance != NULL);
1602
1603 FreePool (OriginalVariable);
1604
1605 if (FoundOne) {
1606 VariableSize = GetDevicePathSize (NewVariable);
1607
1608 Status = gRT->SetVariable (
1609 VariableName,
1610 &gEfiGlobalVariableGuid,
1611 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
1612 VariableSize,
1613 NewVariable
1614 );
1615 //
1616 // Shrinking variable with existing variable driver implementation shouldn't fail.
1617 //
1618 ASSERT_EFI_ERROR (Status);
1619 }
1620
1621 if (NewVariable != NULL) {
1622 FreePool (NewVariable);
1623 }
1624
1625 return ;
1626 }
1627
1628 /**
1629 Build terminal device path according to terminal type.
1630
1631 @param TerminalType The terminal type is PC ANSI, VT100, VT100+ or VT-UTF8.
1632 @param ParentDevicePath Parent device path.
1633 @param TerminalDevicePath Returned terminal device path, if building successfully.
1634
1635 @retval EFI_UNSUPPORTED Terminal does not belong to the supported type.
1636 @retval EFI_OUT_OF_RESOURCES Generate terminal device path failed.
1637 @retval EFI_SUCCESS Build terminal device path successfully.
1638
1639 **/
1640 EFI_STATUS
1641 SetTerminalDevicePath (
1642 IN UINT8 TerminalType,
1643 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
1644 OUT EFI_DEVICE_PATH_PROTOCOL **TerminalDevicePath
1645 )
1646 {
1647 VENDOR_DEVICE_PATH Node;
1648
1649 *TerminalDevicePath = NULL;
1650 Node.Header.Type = MESSAGING_DEVICE_PATH;
1651 Node.Header.SubType = MSG_VENDOR_DP;
1652
1653 //
1654 // Generate terminal device path node according to terminal type.
1655 //
1656 switch (TerminalType) {
1657
1658 case PCANSITYPE:
1659 CopyGuid (&Node.Guid, &gEfiPcAnsiGuid);
1660 break;
1661
1662 case VT100TYPE:
1663 CopyGuid (&Node.Guid, &gEfiVT100Guid);
1664 break;
1665
1666 case VT100PLUSTYPE:
1667 CopyGuid (&Node.Guid, &gEfiVT100PlusGuid);
1668 break;
1669
1670 case VTUTF8TYPE:
1671 CopyGuid (&Node.Guid, &gEfiVTUTF8Guid);
1672 break;
1673
1674 case TTYTERMTYPE:
1675 CopyGuid (&Node.Guid, &gEfiTtyTermGuid);
1676 break;
1677
1678 default:
1679 return EFI_UNSUPPORTED;
1680 }
1681
1682 //
1683 // Get VENDOR_DEVCIE_PATH size and put into Node.Header
1684 //
1685 SetDevicePathNodeLength (
1686 &Node.Header,
1687 sizeof (VENDOR_DEVICE_PATH)
1688 );
1689
1690 //
1691 // Append the terminal node onto parent device path
1692 // to generate a complete terminal device path.
1693 //
1694 *TerminalDevicePath = AppendDevicePathNode (
1695 ParentDevicePath,
1696 (EFI_DEVICE_PATH_PROTOCOL *) &Node
1697 );
1698 if (*TerminalDevicePath == NULL) {
1699 return EFI_OUT_OF_RESOURCES;
1700 }
1701
1702 return EFI_SUCCESS;
1703 }
1704
1705 /**
1706 The user Entry Point for module Terminal. The user code starts with this function.
1707
1708 @param ImageHandle The firmware allocated handle for the EFI image.
1709 @param SystemTable A pointer to the EFI System Table.
1710
1711 @retval EFI_SUCCESS The entry point is executed successfully.
1712 @retval other Some error occurs when executing this entry point.
1713
1714 **/
1715 EFI_STATUS
1716 EFIAPI
1717 InitializeTerminal(
1718 IN EFI_HANDLE ImageHandle,
1719 IN EFI_SYSTEM_TABLE *SystemTable
1720 )
1721 {
1722 EFI_STATUS Status;
1723
1724 //
1725 // Install driver model protocol(s).
1726 //
1727 Status = EfiLibInstallDriverBindingComponentName2 (
1728 ImageHandle,
1729 SystemTable,
1730 &gTerminalDriverBinding,
1731 ImageHandle,
1732 &gTerminalComponentName,
1733 &gTerminalComponentName2
1734 );
1735 ASSERT_EFI_ERROR (Status);
1736
1737 return Status;
1738 }
1739
1740 /**
1741 Check if the device supports hot-plug through its device path.
1742
1743 This function could be updated to check more types of Hot Plug devices.
1744 Currently, it checks USB and PCCard device.
1745
1746 @param DevicePath Pointer to device's device path.
1747
1748 @retval TRUE The devcie is a hot-plug device
1749 @retval FALSE The devcie is not a hot-plug device.
1750
1751 **/
1752 BOOLEAN
1753 IsHotPlugDevice (
1754 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
1755 )
1756 {
1757 EFI_DEVICE_PATH_PROTOCOL *CheckDevicePath;
1758
1759 CheckDevicePath = DevicePath;
1760 while (!IsDevicePathEnd (CheckDevicePath)) {
1761 //
1762 // Check device whether is hot plug device or not throught Device Path
1763 //
1764 if ((DevicePathType (CheckDevicePath) == MESSAGING_DEVICE_PATH) &&
1765 (DevicePathSubType (CheckDevicePath) == MSG_USB_DP ||
1766 DevicePathSubType (CheckDevicePath) == MSG_USB_CLASS_DP ||
1767 DevicePathSubType (CheckDevicePath) == MSG_USB_WWID_DP)) {
1768 //
1769 // If Device is USB device
1770 //
1771 return TRUE;
1772 }
1773 if ((DevicePathType (CheckDevicePath) == HARDWARE_DEVICE_PATH) &&
1774 (DevicePathSubType (CheckDevicePath) == HW_PCCARD_DP)) {
1775 //
1776 // If Device is PCCard
1777 //
1778 return TRUE;
1779 }
1780
1781 CheckDevicePath = NextDevicePathNode (CheckDevicePath);
1782 }
1783
1784 return FALSE;
1785 }
1786