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