]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
MdeModulePkg TerminalDxe: Execute key notify func at TPL_CALLBACK
[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 - 2016, 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 NULL, // EfiKeyFiFoForNotify
79
80 NULL, // ControllerNameTable
81 NULL, // TimerEvent
82 NULL, // TwoSecondTimeOut
83 INPUT_STATE_DEFAULT,
84 RESET_STATE_DEFAULT,
85 {
86 0,
87 0,
88 0
89 },
90 0,
91 FALSE,
92 { // SimpleTextInputEx
93 TerminalConInResetEx,
94 TerminalConInReadKeyStrokeEx,
95 NULL,
96 TerminalConInSetState,
97 TerminalConInRegisterKeyNotify,
98 TerminalConInUnregisterKeyNotify,
99 },
100 { // NotifyList
101 NULL,
102 NULL,
103 },
104 NULL // KeyNotifyProcessEvent
105 };
106
107 TERMINAL_CONSOLE_MODE_DATA mTerminalConsoleModeData[] = {
108 {100, 31},
109 //
110 // New modes can be added here.
111 //
112 };
113
114 /**
115 Test to see if this driver supports Controller.
116
117 @param This Protocol instance pointer.
118 @param Controller Handle of device to test
119 @param RemainingDevicePath Optional parameter use to pick a specific child
120 device to start.
121
122 @retval EFI_SUCCESS This driver supports this device.
123 @retval EFI_ALREADY_STARTED This driver is already running on this device.
124 @retval other This driver does not support this device.
125
126 **/
127 EFI_STATUS
128 EFIAPI
129 TerminalDriverBindingSupported (
130 IN EFI_DRIVER_BINDING_PROTOCOL *This,
131 IN EFI_HANDLE Controller,
132 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
133 )
134 {
135 EFI_STATUS Status;
136 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
137 EFI_SERIAL_IO_PROTOCOL *SerialIo;
138 VENDOR_DEVICE_PATH *Node;
139
140 //
141 // If remaining device path is not NULL, then make sure it is a
142 // device path that describes a terminal communications protocol.
143 //
144 if (RemainingDevicePath != NULL) {
145 //
146 // Check if RemainingDevicePath is the End of Device Path Node,
147 // if yes, go on checking other conditions
148 //
149 if (!IsDevicePathEnd (RemainingDevicePath)) {
150 //
151 // If RemainingDevicePath isn't the End of Device Path Node,
152 // check its validation
153 //
154 Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;
155
156 if (Node->Header.Type != MESSAGING_DEVICE_PATH ||
157 Node->Header.SubType != MSG_VENDOR_DP ||
158 DevicePathNodeLength(&Node->Header) != sizeof(VENDOR_DEVICE_PATH)) {
159
160 return EFI_UNSUPPORTED;
161
162 }
163 //
164 // only supports PC ANSI, VT100, VT100+, VT-UTF8, and TtyTerm terminal types
165 //
166 if (!CompareGuid (&Node->Guid, &gEfiPcAnsiGuid) &&
167 !CompareGuid (&Node->Guid, &gEfiVT100Guid) &&
168 !CompareGuid (&Node->Guid, &gEfiVT100PlusGuid) &&
169 !CompareGuid (&Node->Guid, &gEfiVTUTF8Guid) &&
170 !CompareGuid (&Node->Guid, &gEfiTtyTermGuid)) {
171
172 return EFI_UNSUPPORTED;
173 }
174 }
175 }
176 //
177 // Open the IO Abstraction(s) needed to perform the supported test
178 // The Controller must support the Serial I/O Protocol.
179 // This driver is a bus driver with at most 1 child device, so it is
180 // ok for it to be already started.
181 //
182 Status = gBS->OpenProtocol (
183 Controller,
184 &gEfiSerialIoProtocolGuid,
185 (VOID **) &SerialIo,
186 This->DriverBindingHandle,
187 Controller,
188 EFI_OPEN_PROTOCOL_BY_DRIVER
189 );
190 if (Status == EFI_ALREADY_STARTED) {
191 return EFI_SUCCESS;
192 }
193
194 if (EFI_ERROR (Status)) {
195 return Status;
196 }
197
198 //
199 // Close the I/O Abstraction(s) used to perform the supported test
200 //
201 gBS->CloseProtocol (
202 Controller,
203 &gEfiSerialIoProtocolGuid,
204 This->DriverBindingHandle,
205 Controller
206 );
207
208 //
209 // Open the EFI Device Path protocol needed to perform the supported test
210 //
211 Status = gBS->OpenProtocol (
212 Controller,
213 &gEfiDevicePathProtocolGuid,
214 (VOID **) &ParentDevicePath,
215 This->DriverBindingHandle,
216 Controller,
217 EFI_OPEN_PROTOCOL_BY_DRIVER
218 );
219 if (Status == EFI_ALREADY_STARTED) {
220 return EFI_SUCCESS;
221 }
222
223 if (EFI_ERROR (Status)) {
224 return Status;
225 }
226
227 //
228 // Close protocol, don't use device path protocol in the Support() function
229 //
230 gBS->CloseProtocol (
231 Controller,
232 &gEfiDevicePathProtocolGuid,
233 This->DriverBindingHandle,
234 Controller
235 );
236
237 return Status;
238 }
239
240 /**
241 Build the terminal device path for the child device according to the
242 terminal type.
243
244 @param ParentDevicePath Parent device path.
245 @param RemainingDevicePath A specific child device.
246
247 @return The child device path built.
248
249 **/
250 EFI_DEVICE_PATH_PROTOCOL*
251 EFIAPI
252 BuildTerminalDevpath (
253 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
254 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
255 )
256 {
257 EFI_DEVICE_PATH_PROTOCOL *TerminalDevicePath;
258 UINT8 TerminalType;
259 VENDOR_DEVICE_PATH *Node;
260 EFI_STATUS Status;
261
262 TerminalDevicePath = NULL;
263
264 //
265 // Use the RemainingDevicePath to determine the terminal type
266 //
267 Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;
268 if (Node == NULL) {
269 TerminalType = PcdGet8 (PcdDefaultTerminalType);
270
271 } else if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) {
272
273 TerminalType = PCANSITYPE;
274
275 } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) {
276
277 TerminalType = VT100TYPE;
278
279 } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) {
280
281 TerminalType = VT100PLUSTYPE;
282
283 } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {
284
285 TerminalType = VTUTF8TYPE;
286
287 } else if (CompareGuid (&Node->Guid, &gEfiTtyTermGuid)) {
288
289 TerminalType = TTYTERMTYPE;
290
291 } else {
292 return NULL;
293 }
294
295 //
296 // Build the device path for the child device
297 //
298 Status = SetTerminalDevicePath (
299 TerminalType,
300 ParentDevicePath,
301 &TerminalDevicePath
302 );
303 if (EFI_ERROR (Status)) {
304 return NULL;
305 }
306 return TerminalDevicePath;
307 }
308
309 /**
310 Compare a device path data structure to that of all the nodes of a
311 second device path instance.
312
313 @param Multi A pointer to a multi-instance device path data structure.
314 @param Single A pointer to a single-instance device path data structure.
315
316 @retval TRUE If the Single is contained within Multi.
317 @retval FALSE The Single is not match within Multi.
318
319 **/
320 BOOLEAN
321 MatchDevicePaths (
322 IN EFI_DEVICE_PATH_PROTOCOL *Multi,
323 IN EFI_DEVICE_PATH_PROTOCOL *Single
324 )
325 {
326 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
327 EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
328 UINTN Size;
329
330 DevicePath = Multi;
331 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
332 //
333 // Search for the match of 'Single' in 'Multi'
334 //
335 while (DevicePathInst != NULL) {
336 //
337 // If the single device path is found in multiple device paths,
338 // return success
339 //
340 if (CompareMem (Single, DevicePathInst, Size) == 0) {
341 FreePool (DevicePathInst);
342 return TRUE;
343 }
344
345 FreePool (DevicePathInst);
346 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
347 }
348
349 return FALSE;
350 }
351
352 /**
353 Check whether the terminal device path is in the global variable.
354
355 @param VariableName Pointer to one global variable.
356 @param TerminalDevicePath Pointer to the terminal device's device path.
357
358 @retval TRUE The devcie is in the global variable.
359 @retval FALSE The devcie is not in the global variable.
360
361 **/
362 BOOLEAN
363 IsTerminalInConsoleVariable (
364 IN CHAR16 *VariableName,
365 IN EFI_DEVICE_PATH_PROTOCOL *TerminalDevicePath
366 )
367 {
368 EFI_DEVICE_PATH_PROTOCOL *Variable;
369 BOOLEAN ReturnFlag;
370
371 //
372 // Get global variable and its size according to the name given.
373 //
374 GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);
375 if (Variable == NULL) {
376 return FALSE;
377 }
378
379 //
380 // Check whether the terminal device path is one of the variable instances.
381 //
382 ReturnFlag = MatchDevicePaths (Variable, TerminalDevicePath);
383
384 FreePool (Variable);
385
386 return ReturnFlag;
387 }
388
389 /**
390 Free notify functions list.
391
392 @param ListHead The list head
393
394 @retval EFI_SUCCESS Free the notify list successfully.
395 @retval EFI_INVALID_PARAMETER ListHead is NULL.
396
397 **/
398 EFI_STATUS
399 TerminalFreeNotifyList (
400 IN OUT LIST_ENTRY *ListHead
401 )
402 {
403 TERMINAL_CONSOLE_IN_EX_NOTIFY *NotifyNode;
404
405 if (ListHead == NULL) {
406 return EFI_INVALID_PARAMETER;
407 }
408 while (!IsListEmpty (ListHead)) {
409 NotifyNode = CR (
410 ListHead->ForwardLink,
411 TERMINAL_CONSOLE_IN_EX_NOTIFY,
412 NotifyEntry,
413 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
414 );
415 RemoveEntryList (ListHead->ForwardLink);
416 FreePool (NotifyNode);
417 }
418
419 return EFI_SUCCESS;
420 }
421
422 /**
423 Initialize all the text modes which the terminal console supports.
424
425 It returns information for available text modes that the terminal can support.
426
427 @param[out] TextModeCount The total number of text modes that terminal console supports.
428 @param[out] TextModeData The buffer to the text modes column and row information.
429 Caller is responsible to free it when it's non-NULL.
430
431 @retval EFI_SUCCESS The supporting mode information is returned.
432 @retval EFI_INVALID_PARAMETER The parameters are invalid.
433
434 **/
435 EFI_STATUS
436 InitializeTerminalConsoleTextMode (
437 OUT UINTN *TextModeCount,
438 OUT TERMINAL_CONSOLE_MODE_DATA **TextModeData
439 )
440 {
441 UINTN Index;
442 UINTN Count;
443 TERMINAL_CONSOLE_MODE_DATA *ModeBuffer;
444 TERMINAL_CONSOLE_MODE_DATA *NewModeBuffer;
445 UINTN ValidCount;
446 UINTN ValidIndex;
447
448 if ((TextModeCount == NULL) || (TextModeData == NULL)) {
449 return EFI_INVALID_PARAMETER;
450 }
451
452 Count = sizeof (mTerminalConsoleModeData) / sizeof (TERMINAL_CONSOLE_MODE_DATA);
453
454 //
455 // Get defined mode buffer pointer.
456 //
457 ModeBuffer = mTerminalConsoleModeData;
458
459 //
460 // Here we make sure that the final mode exposed does not include the duplicated modes,
461 // and does not include the invalid modes which exceed the max column and row.
462 // Reserve 2 modes for 80x25, 80x50 of terminal console.
463 //
464 NewModeBuffer = AllocateZeroPool (sizeof (TERMINAL_CONSOLE_MODE_DATA) * (Count + 2));
465 ASSERT (NewModeBuffer != NULL);
466
467 //
468 // Mode 0 and mode 1 is for 80x25, 80x50 according to UEFI spec.
469 //
470 ValidCount = 0;
471
472 NewModeBuffer[ValidCount].Columns = 80;
473 NewModeBuffer[ValidCount].Rows = 25;
474 ValidCount++;
475
476 NewModeBuffer[ValidCount].Columns = 80;
477 NewModeBuffer[ValidCount].Rows = 50;
478 ValidCount++;
479
480 //
481 // Start from mode 2 to put the valid mode other than 80x25 and 80x50 in the output mode buffer.
482 //
483 for (Index = 0; Index < Count; Index++) {
484 if ((ModeBuffer[Index].Columns == 0) || (ModeBuffer[Index].Rows == 0)) {
485 //
486 // Skip the pre-defined mode which is invalid.
487 //
488 continue;
489 }
490 for (ValidIndex = 0; ValidIndex < ValidCount; ValidIndex++) {
491 if ((ModeBuffer[Index].Columns == NewModeBuffer[ValidIndex].Columns) &&
492 (ModeBuffer[Index].Rows == NewModeBuffer[ValidIndex].Rows)) {
493 //
494 // Skip the duplicated mode.
495 //
496 break;
497 }
498 }
499 if (ValidIndex == ValidCount) {
500 NewModeBuffer[ValidCount].Columns = ModeBuffer[Index].Columns;
501 NewModeBuffer[ValidCount].Rows = ModeBuffer[Index].Rows;
502 ValidCount++;
503 }
504 }
505
506 DEBUG_CODE (
507 for (Index = 0; Index < ValidCount; Index++) {
508 DEBUG ((EFI_D_INFO, "Terminal - Mode %d, Column = %d, Row = %d\n",
509 Index, NewModeBuffer[Index].Columns, NewModeBuffer[Index].Rows));
510 }
511 );
512
513 //
514 // Return valid mode count and mode information buffer.
515 //
516 *TextModeCount = ValidCount;
517 *TextModeData = NewModeBuffer;
518 return EFI_SUCCESS;
519 }
520
521 /**
522 Start this driver on Controller by opening a Serial IO protocol,
523 reading Device Path, and creating a child handle with a Simple Text In,
524 Simple Text In Ex and Simple Text Out protocol, and device path protocol.
525 And store Console Device Environment Variables.
526
527 @param This Protocol instance pointer.
528 @param Controller Handle of device to bind driver to
529 @param RemainingDevicePath Optional parameter use to pick a specific child
530 device to start.
531
532 @retval EFI_SUCCESS This driver is added to Controller.
533 @retval EFI_ALREADY_STARTED This driver is already running on Controller.
534 @retval other This driver does not support this device.
535
536 **/
537 EFI_STATUS
538 EFIAPI
539 TerminalDriverBindingStart (
540 IN EFI_DRIVER_BINDING_PROTOCOL *This,
541 IN EFI_HANDLE Controller,
542 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
543 )
544 {
545 EFI_STATUS Status;
546 EFI_SERIAL_IO_PROTOCOL *SerialIo;
547 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
548 VENDOR_DEVICE_PATH *Node;
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 ConInSelected = FALSE;
569 ConOutSelected = FALSE;
570 NullRemaining = FALSE;
571 SimTxtInInstalled = FALSE;
572 SimTxtOutInstalled = FALSE;
573 FirstEnter = FALSE;
574 //
575 // Get the Device Path Protocol to build the device path of the child device
576 //
577 Status = gBS->OpenProtocol (
578 Controller,
579 &gEfiDevicePathProtocolGuid,
580 (VOID **) &ParentDevicePath,
581 This->DriverBindingHandle,
582 Controller,
583 EFI_OPEN_PROTOCOL_BY_DRIVER
584 );
585 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
586 return Status;
587 }
588
589 //
590 // Open the Serial I/O Protocol BY_DRIVER. It might already be started.
591 //
592 Status = gBS->OpenProtocol (
593 Controller,
594 &gEfiSerialIoProtocolGuid,
595 (VOID **) &SerialIo,
596 This->DriverBindingHandle,
597 Controller,
598 EFI_OPEN_PROTOCOL_BY_DRIVER
599 );
600 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
601 return Status;
602 }
603
604 if (Status != EFI_ALREADY_STARTED) {
605 //
606 // the serial I/O protocol never be opened before, it is the first
607 // time to start the serial Io controller
608 //
609 FirstEnter = TRUE;
610 }
611
612 //
613 // Serial I/O is not already open by this driver, then tag the handle
614 // with the Terminal Driver GUID and update the ConInDev, ConOutDev, and
615 // StdErrDev variables with the list of possible terminal types on this
616 // serial port.
617 //
618 Status = gBS->OpenProtocol (
619 Controller,
620 &gEfiCallerIdGuid,
621 NULL,
622 This->DriverBindingHandle,
623 Controller,
624 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
625 );
626 if (EFI_ERROR (Status)) {
627 Status = gBS->InstallMultipleProtocolInterfaces (
628 &Controller,
629 &gEfiCallerIdGuid,
630 DuplicateDevicePath (ParentDevicePath),
631 NULL
632 );
633 if (EFI_ERROR (Status)) {
634 goto Error;
635 }
636
637 if (!IsHotPlugDevice (ParentDevicePath)) {
638 //
639 // if the serial device is a hot plug device, do not update the
640 // ConInDev, ConOutDev, and StdErrDev variables.
641 //
642 TerminalUpdateConsoleDevVariable (L"ConInDev", ParentDevicePath);
643 TerminalUpdateConsoleDevVariable (L"ConOutDev", ParentDevicePath);
644 TerminalUpdateConsoleDevVariable (L"ErrOutDev", ParentDevicePath);
645 }
646 }
647
648 //
649 // Check the requirement for the SimpleTxtIn and SimpleTxtOut protocols
650 //
651 // Simple In/Out Protocol will not be installed onto the handle if the
652 // device path to the handle is not present in the ConIn/ConOut
653 // environment variable. But If RemainingDevicePath is NULL, then always
654 // produce both Simple In and Simple Text Output Protocols. This is required
655 // for the connect all sequences to make sure all possible consoles are
656 // produced no matter what the current values of ConIn, ConOut, or StdErr are.
657 //
658 if (RemainingDevicePath == NULL) {
659 NullRemaining = TRUE;
660 }
661
662 DevicePath = BuildTerminalDevpath (ParentDevicePath, RemainingDevicePath);
663 if (DevicePath != NULL) {
664 ConInSelected = IsTerminalInConsoleVariable (L"ConIn", DevicePath);
665 ConOutSelected = IsTerminalInConsoleVariable (L"ConOut", DevicePath);
666 FreePool (DevicePath);
667 } else {
668 goto Error;
669 }
670 //
671 // Not create the child terminal handle if both Simple In/In Ex and
672 // Simple text Out protocols are not required to be published
673 //
674 if ((!ConInSelected)&&(!ConOutSelected)&&(!NullRemaining)) {
675 goto Error;
676 }
677
678 //
679 // create the child terminal handle during first entry
680 //
681 if (FirstEnter) {
682 //
683 // First enther the start function
684 //
685 FirstEnter = FALSE;
686 //
687 // Make sure a child handle does not already exist. This driver can only
688 // produce one child per serial port.
689 //
690 Status = gBS->OpenProtocolInformation (
691 Controller,
692 &gEfiSerialIoProtocolGuid,
693 &OpenInfoBuffer,
694 &EntryCount
695 );
696 if (!EFI_ERROR (Status)) {
697 Status = EFI_SUCCESS;
698 for (Index = 0; Index < EntryCount; Index++) {
699 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
700 Status = EFI_ALREADY_STARTED;
701 }
702 }
703
704 FreePool (OpenInfoBuffer);
705 if (EFI_ERROR (Status)) {
706 goto Error;
707 }
708 }
709
710 //
711 // If RemainingDevicePath is NULL, use default terminal type
712 //
713 if (RemainingDevicePath == NULL) {
714 TerminalType = PcdGet8 (PcdDefaultTerminalType);
715 //
716 // Must be between PCANSITYPE (0) and TTYTERMTYPE (4)
717 //
718 ASSERT (TerminalType <= TTYTERMTYPE);
719 } else if (!IsDevicePathEnd (RemainingDevicePath)) {
720 //
721 // If RemainingDevicePath isn't the End of Device Path Node,
722 // Use the RemainingDevicePath to determine the terminal type
723 //
724 Node = (VENDOR_DEVICE_PATH *)RemainingDevicePath;
725 if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) {
726 TerminalType = PCANSITYPE;
727 } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) {
728 TerminalType = VT100TYPE;
729 } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) {
730 TerminalType = VT100PLUSTYPE;
731 } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {
732 TerminalType = VTUTF8TYPE;
733 } else if (CompareGuid (&Node->Guid, &gEfiTtyTermGuid)) {
734 TerminalType = TTYTERMTYPE;
735 } else {
736 goto Error;
737 }
738 } else {
739 //
740 // If RemainingDevicePath is the End of Device Path Node,
741 // skip enumerate any device and return EFI_SUCESSS
742 //
743 return EFI_SUCCESS;
744 }
745
746 //
747 // Initialize the Terminal Dev
748 //
749 TerminalDevice = AllocateCopyPool (sizeof (TERMINAL_DEV), &mTerminalDevTemplate);
750 if (TerminalDevice == NULL) {
751 Status = EFI_OUT_OF_RESOURCES;
752 goto Error;
753 }
754
755 TerminalDevice->TerminalType = TerminalType;
756 TerminalDevice->SerialIo = SerialIo;
757
758 InitializeListHead (&TerminalDevice->NotifyList);
759 Status = gBS->CreateEvent (
760 EVT_NOTIFY_WAIT,
761 TPL_NOTIFY,
762 TerminalConInWaitForKeyEx,
763 TerminalDevice,
764 &TerminalDevice->SimpleInputEx.WaitForKeyEx
765 );
766 if (EFI_ERROR (Status)) {
767 goto Error;
768 }
769
770 Status = gBS->CreateEvent (
771 EVT_NOTIFY_WAIT,
772 TPL_NOTIFY,
773 TerminalConInWaitForKey,
774 TerminalDevice,
775 &TerminalDevice->SimpleInput.WaitForKey
776 );
777 if (EFI_ERROR (Status)) {
778 goto Error;
779 }
780 //
781 // Allocates and initializes the FIFO buffer to be zero, used for accommodating
782 // the pre-read pending characters.
783 //
784 TerminalDevice->RawFiFo = AllocateZeroPool (sizeof (RAW_DATA_FIFO));
785 if (TerminalDevice->RawFiFo == NULL) {
786 goto Error;
787 }
788 TerminalDevice->UnicodeFiFo = AllocateZeroPool (sizeof (UNICODE_FIFO));
789 if (TerminalDevice->UnicodeFiFo == NULL) {
790 goto Error;
791 }
792 TerminalDevice->EfiKeyFiFo = AllocateZeroPool (sizeof (EFI_KEY_FIFO));
793 if (TerminalDevice->EfiKeyFiFo == NULL) {
794 goto Error;
795 }
796 TerminalDevice->EfiKeyFiFoForNotify = AllocateZeroPool (sizeof (EFI_KEY_FIFO));
797 if (TerminalDevice->EfiKeyFiFoForNotify == 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->CreateEvent (
1010 EVT_NOTIFY_SIGNAL,
1011 TPL_CALLBACK,
1012 KeyNotifyProcessHandler,
1013 TerminalDevice,
1014 &TerminalDevice->KeyNotifyProcessEvent
1015 );
1016 ASSERT_EFI_ERROR (Status);
1017
1018 Status = gBS->InstallProtocolInterface (
1019 &TerminalDevice->Handle,
1020 &gEfiDevicePathProtocolGuid,
1021 EFI_NATIVE_INTERFACE,
1022 TerminalDevice->DevicePath
1023 );
1024 if (EFI_ERROR (Status)) {
1025 goto Error;
1026 }
1027
1028 //
1029 // Register the Parent-Child relationship via
1030 // EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
1031 //
1032 Status = gBS->OpenProtocol (
1033 Controller,
1034 &gEfiSerialIoProtocolGuid,
1035 (VOID **) &TerminalDevice->SerialIo,
1036 This->DriverBindingHandle,
1037 TerminalDevice->Handle,
1038 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1039 );
1040 if (EFI_ERROR (Status)) {
1041 goto Error;
1042 }
1043 }
1044
1045 //
1046 // Find the child handle, and get its TerminalDevice private data
1047 //
1048 Status = gBS->OpenProtocolInformation (
1049 Controller,
1050 &gEfiSerialIoProtocolGuid,
1051 &OpenInfoBuffer,
1052 &EntryCount
1053 );
1054 if (!EFI_ERROR (Status)) {
1055 Status = EFI_NOT_FOUND;
1056 ASSERT (OpenInfoBuffer != NULL);
1057 for (Index = 0; Index < EntryCount; Index++) {
1058 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
1059 //
1060 // Find the child terminal handle.
1061 // Test whether the SimpleTxtIn and SimpleTxtOut have been published
1062 //
1063 Status = gBS->OpenProtocol (
1064 OpenInfoBuffer[Index].ControllerHandle,
1065 &gEfiSimpleTextInProtocolGuid,
1066 (VOID **) &SimpleTextInput,
1067 This->DriverBindingHandle,
1068 OpenInfoBuffer[Index].ControllerHandle,
1069 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1070 );
1071 if (!EFI_ERROR (Status)) {
1072 SimTxtInInstalled = TRUE;
1073 TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (SimpleTextInput);
1074 }
1075
1076 Status = gBS->OpenProtocol (
1077 OpenInfoBuffer[Index].ControllerHandle,
1078 &gEfiSimpleTextOutProtocolGuid,
1079 (VOID **) &SimpleTextOutput,
1080 This->DriverBindingHandle,
1081 OpenInfoBuffer[Index].ControllerHandle,
1082 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1083 );
1084 if (!EFI_ERROR (Status)) {
1085 SimTxtOutInstalled = TRUE;
1086 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);
1087 }
1088 Status = EFI_SUCCESS;
1089 break;
1090 }
1091 }
1092
1093 FreePool (OpenInfoBuffer);
1094 if (EFI_ERROR (Status)) {
1095 goto ReportError;
1096 }
1097 } else {
1098 goto ReportError;
1099 }
1100
1101 ASSERT (TerminalDevice != NULL);
1102 //
1103 // Only do the reset if the device path is in the Conout variable
1104 //
1105 if (ConInSelected && !SimTxtInInstalled) {
1106 Status = TerminalDevice->SimpleInput.Reset (
1107 &TerminalDevice->SimpleInput,
1108 FALSE
1109 );
1110 if (EFI_ERROR (Status)) {
1111 //
1112 // Need to report Error Code first
1113 //
1114 goto ReportError;
1115 }
1116 }
1117
1118 //
1119 // Only output the configure string to remote terminal if the device path
1120 // is in the Conout variable
1121 //
1122 if (ConOutSelected && !SimTxtOutInstalled) {
1123 Status = TerminalDevice->SimpleTextOutput.SetAttribute (
1124 &TerminalDevice->SimpleTextOutput,
1125 EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)
1126 );
1127 if (EFI_ERROR (Status)) {
1128 goto ReportError;
1129 }
1130
1131 Status = TerminalDevice->SimpleTextOutput.Reset (
1132 &TerminalDevice->SimpleTextOutput,
1133 FALSE
1134 );
1135 if (EFI_ERROR (Status)) {
1136 goto ReportError;
1137 }
1138
1139 Status = TerminalDevice->SimpleTextOutput.SetMode (
1140 &TerminalDevice->SimpleTextOutput,
1141 0
1142 );
1143 if (EFI_ERROR (Status)) {
1144 goto ReportError;
1145 }
1146
1147 Status = TerminalDevice->SimpleTextOutput.EnableCursor (
1148 &TerminalDevice->SimpleTextOutput,
1149 TRUE
1150 );
1151 if (EFI_ERROR (Status)) {
1152 goto ReportError;
1153 }
1154 }
1155
1156 //
1157 // Simple In/Out Protocol will not be installed onto the handle if the
1158 // device path to the handle is not present in the ConIn/ConOut
1159 // environment variable. But If RemainingDevicePath is NULL, then always
1160 // produce both Simple In and Simple Text Output Protocols. This is required
1161 // for the connect all sequences to make sure all possible consoles are
1162 // produced no matter what the current values of ConIn, ConOut, or StdErr are.
1163 //
1164 if (!SimTxtInInstalled && (ConInSelected || NullRemaining)) {
1165 Status = gBS->InstallMultipleProtocolInterfaces (
1166 &TerminalDevice->Handle,
1167 &gEfiSimpleTextInProtocolGuid,
1168 &TerminalDevice->SimpleInput,
1169 &gEfiSimpleTextInputExProtocolGuid,
1170 &TerminalDevice->SimpleInputEx,
1171 NULL
1172 );
1173 if (EFI_ERROR (Status)) {
1174 goto Error;
1175 }
1176 }
1177
1178 if (!SimTxtOutInstalled && (ConOutSelected || NullRemaining)) {
1179 Status = gBS->InstallProtocolInterface (
1180 &TerminalDevice->Handle,
1181 &gEfiSimpleTextOutProtocolGuid,
1182 EFI_NATIVE_INTERFACE,
1183 &TerminalDevice->SimpleTextOutput
1184 );
1185 if (EFI_ERROR (Status)) {
1186 goto Error;
1187 }
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 if (TerminalDevice->EfiKeyFiFoForNotify != NULL) {
1241 FreePool (TerminalDevice->EfiKeyFiFoForNotify);
1242 }
1243
1244 if (TerminalDevice->ControllerNameTable != NULL) {
1245 FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
1246 }
1247
1248 if (TerminalDevice->DevicePath != NULL) {
1249 FreePool (TerminalDevice->DevicePath);
1250 }
1251
1252 if (TerminalDevice->TerminalConsoleModeData != NULL) {
1253 FreePool (TerminalDevice->TerminalConsoleModeData);
1254 }
1255
1256 FreePool (TerminalDevice);
1257 }
1258 }
1259
1260 This->Stop (This, Controller, 0, NULL);
1261
1262 return Status;
1263 }
1264
1265 /**
1266 Stop this driver on Controller by closing Simple Text In, Simple Text
1267 In Ex, Simple Text Out protocol, and removing parent device path from
1268 Console Device Environment Variables.
1269
1270 @param This Protocol instance pointer.
1271 @param Controller Handle of device to stop driver on
1272 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
1273 children is zero stop the entire bus driver.
1274 @param ChildHandleBuffer List of Child Handles to Stop.
1275
1276 @retval EFI_SUCCESS This driver is removed Controller.
1277 @retval other This driver could not be removed from this device.
1278
1279 **/
1280 EFI_STATUS
1281 EFIAPI
1282 TerminalDriverBindingStop (
1283 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1284 IN EFI_HANDLE Controller,
1285 IN UINTN NumberOfChildren,
1286 IN EFI_HANDLE *ChildHandleBuffer
1287 )
1288 {
1289 EFI_STATUS Status;
1290 UINTN Index;
1291 BOOLEAN AllChildrenStopped;
1292 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;
1293 TERMINAL_DEV *TerminalDevice;
1294 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
1295 EFI_SERIAL_IO_PROTOCOL *SerialIo;
1296 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1297
1298 Status = gBS->HandleProtocol (
1299 Controller,
1300 &gEfiDevicePathProtocolGuid,
1301 (VOID **) &DevicePath
1302 );
1303 if (EFI_ERROR (Status)) {
1304 return Status;
1305 }
1306
1307 //
1308 // Complete all outstanding transactions to Controller.
1309 // Don't allow any new transaction to Controller to be started.
1310 //
1311 if (NumberOfChildren == 0) {
1312 //
1313 // Close the bus driver
1314 //
1315 Status = gBS->OpenProtocol (
1316 Controller,
1317 &gEfiCallerIdGuid,
1318 (VOID **) &ParentDevicePath,
1319 This->DriverBindingHandle,
1320 Controller,
1321 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1322 );
1323 if (!EFI_ERROR (Status)) {
1324 //
1325 // Remove Parent Device Path from
1326 // the Console Device Environment Variables
1327 //
1328 TerminalRemoveConsoleDevVariable (L"ConInDev", ParentDevicePath);
1329 TerminalRemoveConsoleDevVariable (L"ConOutDev", ParentDevicePath);
1330 TerminalRemoveConsoleDevVariable (L"ErrOutDev", ParentDevicePath);
1331
1332 //
1333 // Uninstall the Terminal Driver's GUID Tag from the Serial controller
1334 //
1335 Status = gBS->UninstallMultipleProtocolInterfaces (
1336 Controller,
1337 &gEfiCallerIdGuid,
1338 ParentDevicePath,
1339 NULL
1340 );
1341
1342 //
1343 // Free the ParentDevicePath that was duplicated in Start()
1344 //
1345 if (!EFI_ERROR (Status)) {
1346 FreePool (ParentDevicePath);
1347 }
1348 }
1349
1350 gBS->CloseProtocol (
1351 Controller,
1352 &gEfiSerialIoProtocolGuid,
1353 This->DriverBindingHandle,
1354 Controller
1355 );
1356
1357 gBS->CloseProtocol (
1358 Controller,
1359 &gEfiDevicePathProtocolGuid,
1360 This->DriverBindingHandle,
1361 Controller
1362 );
1363
1364 return EFI_SUCCESS;
1365 }
1366
1367 AllChildrenStopped = TRUE;
1368
1369 for (Index = 0; Index < NumberOfChildren; Index++) {
1370
1371 Status = gBS->OpenProtocol (
1372 ChildHandleBuffer[Index],
1373 &gEfiSimpleTextOutProtocolGuid,
1374 (VOID **) &SimpleTextOutput,
1375 This->DriverBindingHandle,
1376 ChildHandleBuffer[Index],
1377 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1378 );
1379 if (!EFI_ERROR (Status)) {
1380
1381 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);
1382
1383 gBS->CloseProtocol (
1384 Controller,
1385 &gEfiSerialIoProtocolGuid,
1386 This->DriverBindingHandle,
1387 ChildHandleBuffer[Index]
1388 );
1389
1390 Status = gBS->UninstallMultipleProtocolInterfaces (
1391 ChildHandleBuffer[Index],
1392 &gEfiSimpleTextInProtocolGuid,
1393 &TerminalDevice->SimpleInput,
1394 &gEfiSimpleTextInputExProtocolGuid,
1395 &TerminalDevice->SimpleInputEx,
1396 &gEfiSimpleTextOutProtocolGuid,
1397 &TerminalDevice->SimpleTextOutput,
1398 &gEfiDevicePathProtocolGuid,
1399 TerminalDevice->DevicePath,
1400 NULL
1401 );
1402 if (EFI_ERROR (Status)) {
1403 gBS->OpenProtocol (
1404 Controller,
1405 &gEfiSerialIoProtocolGuid,
1406 (VOID **) &SerialIo,
1407 This->DriverBindingHandle,
1408 ChildHandleBuffer[Index],
1409 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1410 );
1411 } else {
1412
1413 if (TerminalDevice->ControllerNameTable != NULL) {
1414 FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
1415 }
1416
1417 gBS->CloseEvent (TerminalDevice->TimerEvent);
1418 gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);
1419 gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);
1420 gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);
1421 gBS->CloseEvent (TerminalDevice->KeyNotifyProcessEvent);
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