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