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