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