]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
Clean codes per ECC for TerminalDxe module.
[mirror_edk2.git] / MdeModulePkg / Universal / Console / TerminalDxe / Terminal.c
1 /** @file
2 Produces Simple Text Input Protocl, Simple Text Input Extended Protocol and
3 Simple Text Output Protocol upon Serial IO Protocol.
4
5 Copyright (c) 2006 - 2008, Intel Corporation. <BR>
6 All rights reserved. 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 EFI_STATUS
20 TerminalFreeNotifyList (
21 IN OUT LIST_ENTRY *ListHead
22 );
23
24 //
25 // Globals
26 //
27 EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding = {
28 TerminalDriverBindingSupported,
29 TerminalDriverBindingStart,
30 TerminalDriverBindingStop,
31 0xa,
32 NULL,
33 NULL
34 };
35
36
37 EFI_GUID *gTerminalType[] = {
38 &gEfiPcAnsiGuid,
39 &gEfiVT100Guid,
40 &gEfiVT100PlusGuid,
41 &gEfiVTUTF8Guid
42 };
43
44
45 TERMINAL_DEV gTerminalDevTemplate = {
46 TERMINAL_DEV_SIGNATURE,
47 NULL,
48 0,
49 NULL,
50 NULL,
51 { // SimpleTextInput
52 TerminalConInReset,
53 TerminalConInReadKeyStroke,
54 NULL
55 },
56 { // SimpleTextOutput
57 TerminalConOutReset,
58 TerminalConOutOutputString,
59 TerminalConOutTestString,
60 TerminalConOutQueryMode,
61 TerminalConOutSetMode,
62 TerminalConOutSetAttribute,
63 TerminalConOutClearScreen,
64 TerminalConOutSetCursorPosition,
65 TerminalConOutEnableCursor,
66 NULL
67 },
68 { // SimpleTextOutputMode
69 1, // MaxMode
70 0, // Mode?
71 EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK), // Attribute
72 0, // CursorColumn
73 0, // CursorRow
74 TRUE // CursorVisible
75 },
76 0,
77 {
78 0,
79 0,
80 { 0 }
81 },
82 {
83 0,
84 0,
85 { 0 }
86 },
87 {
88 0,
89 0,
90 { {0} }
91 },
92 NULL, // ControllerNameTable
93 NULL,
94 INPUT_STATE_DEFAULT,
95 RESET_STATE_DEFAULT,
96 FALSE,
97 { // SimpleTextInputEx
98 TerminalConInResetEx,
99 TerminalConInReadKeyStrokeEx,
100 NULL,
101 TerminalConInSetState,
102 TerminalConInRegisterKeyNotify,
103 TerminalConInUnregisterKeyNotify,
104 },
105 {
106 NULL,
107 NULL,
108 }
109 };
110
111
112
113 EFI_STATUS
114 EFIAPI
115 TerminalDriverBindingSupported (
116 IN EFI_DRIVER_BINDING_PROTOCOL *This,
117 IN EFI_HANDLE Controller,
118 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
119 )
120 {
121 EFI_STATUS Status;
122 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
123 EFI_SERIAL_IO_PROTOCOL *SerialIo;
124 VENDOR_DEVICE_PATH *Node;
125
126 //
127 // If remaining device path is not NULL, then make sure it is a
128 // device path that describes a terminal communications protocol.
129 //
130 if (RemainingDevicePath != NULL) {
131
132 Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;
133
134 if (Node->Header.Type != MESSAGING_DEVICE_PATH ||
135 Node->Header.SubType != MSG_VENDOR_DP ||
136 DevicePathNodeLength(&Node->Header) != sizeof(VENDOR_DEVICE_PATH)) {
137
138 return EFI_UNSUPPORTED;
139
140 }
141 //
142 // only supports PC ANSI, VT100, VT100+ and VT-UTF8 terminal types
143 //
144 if (!CompareGuid (&Node->Guid, &gEfiPcAnsiGuid) &&
145 !CompareGuid (&Node->Guid, &gEfiVT100Guid) &&
146 !CompareGuid (&Node->Guid, &gEfiVT100PlusGuid) &&
147 !CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {
148
149 return EFI_UNSUPPORTED;
150 }
151 }
152 //
153 // Open the IO Abstraction(s) needed to perform the supported test
154 //
155 Status = gBS->OpenProtocol (
156 Controller,
157 &gEfiDevicePathProtocolGuid,
158 (VOID **) &ParentDevicePath,
159 This->DriverBindingHandle,
160 Controller,
161 EFI_OPEN_PROTOCOL_BY_DRIVER
162 );
163 if (Status == EFI_ALREADY_STARTED) {
164 return EFI_SUCCESS;
165 }
166
167 if (EFI_ERROR (Status)) {
168 return Status;
169 }
170
171 gBS->CloseProtocol (
172 Controller,
173 &gEfiDevicePathProtocolGuid,
174 This->DriverBindingHandle,
175 Controller
176 );
177
178 //
179 // The Controller must support the Serial I/O Protocol.
180 // This driver is a bus driver with at most 1 child device, so it is
181 // ok for it to be already started.
182 //
183 Status = gBS->OpenProtocol (
184 Controller,
185 &gEfiSerialIoProtocolGuid,
186 (VOID **) &SerialIo,
187 This->DriverBindingHandle,
188 Controller,
189 EFI_OPEN_PROTOCOL_BY_DRIVER
190 );
191 if (Status == EFI_ALREADY_STARTED) {
192 return EFI_SUCCESS;
193 }
194
195 if (EFI_ERROR (Status)) {
196 return Status;
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 return Status;
209 }
210
211
212 /**
213 Start the controller.
214
215 @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
216 instance.
217 @param Controller The handle of the controller to start.
218 @param RemainingDevicePath A pointer to the remaining portion of a devcie
219 path.
220
221 @return EFI_SUCCESS.
222
223 **/
224 EFI_STATUS
225 EFIAPI
226 TerminalDriverBindingStart (
227 IN EFI_DRIVER_BINDING_PROTOCOL *This,
228 IN EFI_HANDLE Controller,
229 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
230 )
231 {
232 EFI_STATUS Status;
233 EFI_SERIAL_IO_PROTOCOL *SerialIo;
234 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
235 VENDOR_DEVICE_PATH *Node;
236 VENDOR_DEVICE_PATH *DefaultNode;
237 EFI_SERIAL_IO_MODE *Mode;
238 UINTN SerialInTimeOut;
239 TERMINAL_DEV *TerminalDevice;
240 UINT8 TerminalType;
241 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
242 UINTN EntryCount;
243 UINTN Index;
244 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
245
246 TerminalDevice = NULL;
247 DefaultNode = NULL;
248 //
249 // Get the Device Path Protocol to build the device path of the child device
250 //
251 Status = gBS->OpenProtocol (
252 Controller,
253 &gEfiDevicePathProtocolGuid,
254 (VOID **) &ParentDevicePath,
255 This->DriverBindingHandle,
256 Controller,
257 EFI_OPEN_PROTOCOL_BY_DRIVER
258 );
259 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
260 return Status;
261 }
262
263 //
264 // Open the Serial I/O Protocol BY_DRIVER. It might already be started.
265 //
266 Status = gBS->OpenProtocol (
267 Controller,
268 &gEfiSerialIoProtocolGuid,
269 (VOID **) &SerialIo,
270 This->DriverBindingHandle,
271 Controller,
272 EFI_OPEN_PROTOCOL_BY_DRIVER
273 );
274 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
275 return Status;
276 }
277
278 if (Status != EFI_ALREADY_STARTED) {
279 //
280 // If Serial I/O is not already open by this driver, then tag the handle
281 // with the Terminal Driver GUID and update the ConInDev, ConOutDev, and
282 // StdErrDev variables with the list of possible terminal types on this
283 // serial port.
284 //
285 Status = gBS->OpenProtocol (
286 Controller,
287 &gEfiCallerIdGuid,
288 NULL,
289 This->DriverBindingHandle,
290 Controller,
291 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
292 );
293 if (EFI_ERROR (Status)) {
294 Status = gBS->InstallMultipleProtocolInterfaces (
295 &Controller,
296 &gEfiCallerIdGuid,
297 DuplicateDevicePath (ParentDevicePath),
298 NULL
299 );
300 if (EFI_ERROR (Status)) {
301 goto Error;
302 }
303 //
304 // if the serial device is a hot plug device, do not update the
305 // ConInDev, ConOutDev, and StdErrDev variables.
306 //
307 Status = gBS->OpenProtocol (
308 Controller,
309 &gEfiHotPlugDeviceGuid,
310 NULL,
311 This->DriverBindingHandle,
312 Controller,
313 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
314 );
315 if (EFI_ERROR (Status)) {
316 TerminalUpdateConsoleDevVariable (L"ConInDev", ParentDevicePath);
317 TerminalUpdateConsoleDevVariable (L"ConOutDev", ParentDevicePath);
318 TerminalUpdateConsoleDevVariable (L"ErrOutDev", ParentDevicePath);
319 }
320 }
321 }
322 //
323 // Make sure a child handle does not already exist. This driver can only
324 // produce one child per serial port.
325 //
326 Status = gBS->OpenProtocolInformation (
327 Controller,
328 &gEfiSerialIoProtocolGuid,
329 &OpenInfoBuffer,
330 &EntryCount
331 );
332 if (!EFI_ERROR (Status)) {
333 Status = EFI_SUCCESS;
334 for (Index = 0; Index < EntryCount; Index++) {
335 if (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
336 Status = EFI_ALREADY_STARTED;
337 }
338 }
339
340 FreePool (OpenInfoBuffer);
341 if (EFI_ERROR (Status)) {
342 return Status;
343 }
344 }
345 //
346 // If RemainingDevicePath is NULL, then create default device path node
347 //
348 if (RemainingDevicePath == NULL) {
349 DefaultNode = AllocateZeroPool (sizeof (VENDOR_DEVICE_PATH));
350 if (DefaultNode == NULL) {
351 Status = EFI_OUT_OF_RESOURCES;
352 goto Error;
353 }
354
355 TerminalType = FixedPcdGet8 (PcdDefaultTerminalType);
356 // must be between PCANSITYPE (0) and VTUTF8TYPE (3)
357 ASSERT (TerminalType <= VTUTF8TYPE);
358
359 CopyMem (&DefaultNode->Guid, gTerminalType[TerminalType], sizeof (EFI_GUID));
360 RemainingDevicePath = (EFI_DEVICE_PATH_PROTOCOL*)DefaultNode;
361 } else {
362 //
363 // Use the RemainingDevicePath to determine the terminal type
364 //
365 Node = (VENDOR_DEVICE_PATH *)RemainingDevicePath;
366 if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) {
367 TerminalType = PCANSITYPE;
368 } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) {
369 TerminalType = VT100TYPE;
370 } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) {
371 TerminalType = VT100PLUSTYPE;
372 } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {
373 TerminalType = VTUTF8TYPE;
374 } else {
375 goto Error;
376 }
377 }
378
379 //
380 // Initialize the Terminal Dev
381 //
382 TerminalDevice = AllocateCopyPool (sizeof (TERMINAL_DEV), &gTerminalDevTemplate);
383 if (TerminalDevice == NULL) {
384 Status = EFI_OUT_OF_RESOURCES;
385 goto Error;
386 }
387
388 TerminalDevice->TerminalType = TerminalType;
389 TerminalDevice->SerialIo = SerialIo;
390
391 InitializeListHead (&TerminalDevice->NotifyList);
392 Status = gBS->CreateEvent (
393 EVT_NOTIFY_WAIT,
394 TPL_NOTIFY,
395 TerminalConInWaitForKeyEx,
396 &TerminalDevice->SimpleInputEx,
397 &TerminalDevice->SimpleInputEx.WaitForKeyEx
398 );
399 if (EFI_ERROR (Status)) {
400 goto Error;
401 }
402
403
404 Status = gBS->CreateEvent (
405 EVT_NOTIFY_WAIT,
406 TPL_NOTIFY,
407 TerminalConInWaitForKey,
408 &TerminalDevice->SimpleInput,
409 &TerminalDevice->SimpleInput.WaitForKey
410 );
411 if (EFI_ERROR (Status)) {
412 goto Error;
413 }
414 //
415 // initialize the FIFO buffer used for accommodating
416 // the pre-read pending characters
417 //
418 InitializeRawFiFo (TerminalDevice);
419 InitializeUnicodeFiFo (TerminalDevice);
420 InitializeEfiKeyFiFo (TerminalDevice);
421
422 //
423 // Set the timeout value of serial buffer for
424 // keystroke response performance issue
425 //
426 Mode = TerminalDevice->SerialIo->Mode;
427
428 SerialInTimeOut = 0;
429 if (Mode->BaudRate != 0) {
430 SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate;
431 }
432
433 Status = TerminalDevice->SerialIo->SetAttributes (
434 TerminalDevice->SerialIo,
435 Mode->BaudRate,
436 Mode->ReceiveFifoDepth,
437 (UINT32) SerialInTimeOut,
438 (EFI_PARITY_TYPE) (Mode->Parity),
439 (UINT8) Mode->DataBits,
440 (EFI_STOP_BITS_TYPE) (Mode->StopBits)
441 );
442 if (EFI_ERROR (Status)) {
443 //
444 // if set attributes operation fails, invalidate
445 // the value of SerialInTimeOut,thus make it
446 // inconsistent with the default timeout value
447 // of serial buffer. This will invoke the recalculation
448 // in the readkeystroke routine.
449 //
450 TerminalDevice->SerialInTimeOut = 0;
451 } else {
452 TerminalDevice->SerialInTimeOut = SerialInTimeOut;
453 }
454 //
455 // Build the device path for the child device
456 //
457 Status = SetTerminalDevicePath (
458 TerminalDevice->TerminalType,
459 ParentDevicePath,
460 &TerminalDevice->DevicePath
461 );
462 if (EFI_ERROR (Status)) {
463 goto Error;
464 }
465
466 DevicePath = TerminalDevice->DevicePath;
467
468 Status = TerminalDevice->SimpleInput.Reset (
469 &TerminalDevice->SimpleInput,
470 FALSE
471 );
472 if (EFI_ERROR (Status)) {
473 //
474 // Need to report Error Code first
475 //
476 goto ReportError;
477 }
478 //
479 // Simple Text Output Protocol
480 //
481 TerminalDevice->SimpleTextOutput.Reset = TerminalConOutReset;
482 TerminalDevice->SimpleTextOutput.OutputString = TerminalConOutOutputString;
483 TerminalDevice->SimpleTextOutput.TestString = TerminalConOutTestString;
484 TerminalDevice->SimpleTextOutput.QueryMode = TerminalConOutQueryMode;
485 TerminalDevice->SimpleTextOutput.SetMode = TerminalConOutSetMode;
486 TerminalDevice->SimpleTextOutput.SetAttribute = TerminalConOutSetAttribute;
487 TerminalDevice->SimpleTextOutput.ClearScreen = TerminalConOutClearScreen;
488 TerminalDevice->SimpleTextOutput.SetCursorPosition = TerminalConOutSetCursorPosition;
489 TerminalDevice->SimpleTextOutput.EnableCursor = TerminalConOutEnableCursor;
490 TerminalDevice->SimpleTextOutput.Mode = &TerminalDevice->SimpleTextOutputMode;
491
492 TerminalDevice->SimpleTextOutputMode.MaxMode = 3;
493 //
494 // For terminal devices, cursor is always visible
495 //
496 TerminalDevice->SimpleTextOutputMode.CursorVisible = TRUE;
497 Status = TerminalDevice->SimpleTextOutput.SetAttribute (
498 &TerminalDevice->SimpleTextOutput,
499 EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)
500 );
501 if (EFI_ERROR (Status)) {
502 goto ReportError;
503 }
504
505 Status = TerminalDevice->SimpleTextOutput.Reset (
506 &TerminalDevice->SimpleTextOutput,
507 FALSE
508 );
509 if (EFI_ERROR (Status)) {
510 goto ReportError;
511 }
512
513 Status = TerminalDevice->SimpleTextOutput.SetMode (
514 &TerminalDevice->SimpleTextOutput,
515 0
516 );
517 if (EFI_ERROR (Status)) {
518 goto ReportError;
519 }
520
521 Status = TerminalDevice->SimpleTextOutput.EnableCursor (
522 &TerminalDevice->SimpleTextOutput,
523 TRUE
524 );
525 if (EFI_ERROR (Status)) {
526 goto ReportError;
527 }
528
529 Status = gBS->CreateEvent (
530 EVT_TIMER,
531 TPL_CALLBACK,
532 NULL,
533 NULL,
534 &TerminalDevice->TwoSecondTimeOut
535 );
536
537 //
538 // Build the component name for the child device
539 //
540 TerminalDevice->ControllerNameTable = NULL;
541 switch (TerminalDevice->TerminalType) {
542 case PCANSITYPE:
543 AddUnicodeString2 (
544 "eng",
545 gTerminalComponentName.SupportedLanguages,
546 &TerminalDevice->ControllerNameTable,
547 (CHAR16 *)L"PC-ANSI Serial Console",
548 TRUE
549 );
550 AddUnicodeString2 (
551 "en",
552 gTerminalComponentName2.SupportedLanguages,
553 &TerminalDevice->ControllerNameTable,
554 (CHAR16 *)L"PC-ANSI Serial Console",
555 FALSE
556 );
557
558 break;
559
560 case VT100TYPE:
561 AddUnicodeString2 (
562 "eng",
563 gTerminalComponentName.SupportedLanguages,
564 &TerminalDevice->ControllerNameTable,
565 (CHAR16 *)L"VT-100 Serial Console",
566 TRUE
567 );
568 AddUnicodeString2 (
569 "en",
570 gTerminalComponentName2.SupportedLanguages,
571 &TerminalDevice->ControllerNameTable,
572 (CHAR16 *)L"VT-100 Serial Console",
573 FALSE
574 );
575
576 break;
577
578 case VT100PLUSTYPE:
579 AddUnicodeString2 (
580 "eng",
581 gTerminalComponentName.SupportedLanguages,
582 &TerminalDevice->ControllerNameTable,
583 (CHAR16 *)L"VT-100+ Serial Console",
584 TRUE
585 );
586 AddUnicodeString2 (
587 "en",
588 gTerminalComponentName2.SupportedLanguages,
589 &TerminalDevice->ControllerNameTable,
590 (CHAR16 *)L"VT-100+ Serial Console",
591 FALSE
592 );
593
594 break;
595
596 case VTUTF8TYPE:
597 AddUnicodeString2 (
598 "eng",
599 gTerminalComponentName.SupportedLanguages,
600 &TerminalDevice->ControllerNameTable,
601 (CHAR16 *)L"VT-UTF8 Serial Console",
602 TRUE
603 );
604 AddUnicodeString2 (
605 "en",
606 gTerminalComponentName2.SupportedLanguages,
607 &TerminalDevice->ControllerNameTable,
608 (CHAR16 *)L"VT-UTF8 Serial Console",
609 FALSE
610 );
611
612 break;
613 }
614 //
615 // Install protocol interfaces for the serial device.
616 //
617 Status = gBS->InstallMultipleProtocolInterfaces (
618 &TerminalDevice->Handle,
619 &gEfiDevicePathProtocolGuid,
620 TerminalDevice->DevicePath,
621 &gEfiSimpleTextInProtocolGuid,
622 &TerminalDevice->SimpleInput,
623 &gEfiSimpleTextInputExProtocolGuid,
624 &TerminalDevice->SimpleInputEx,
625 &gEfiSimpleTextOutProtocolGuid,
626 &TerminalDevice->SimpleTextOutput,
627 NULL
628 );
629 if (EFI_ERROR (Status)) {
630 goto Error;
631 }
632 //
633 // if the serial device is a hot plug device, attaches the HotPlugGuid
634 // onto the terminal device handle.
635 //
636 Status = gBS->OpenProtocol (
637 Controller,
638 &gEfiHotPlugDeviceGuid,
639 NULL,
640 This->DriverBindingHandle,
641 Controller,
642 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
643 );
644 if (!EFI_ERROR (Status)) {
645 Status = gBS->InstallMultipleProtocolInterfaces (
646 &TerminalDevice->Handle,
647 &gEfiHotPlugDeviceGuid,
648 NULL,
649 NULL
650 );
651 }
652 //
653 // Register the Parent-Child relationship via
654 // EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
655 //
656 Status = gBS->OpenProtocol (
657 Controller,
658 &gEfiSerialIoProtocolGuid,
659 (VOID **) &TerminalDevice->SerialIo,
660 This->DriverBindingHandle,
661 TerminalDevice->Handle,
662 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
663 );
664 if (EFI_ERROR (Status)) {
665 goto Error;
666 }
667
668 if (DefaultNode != NULL) {
669 FreePool (DefaultNode);
670 }
671
672 return EFI_SUCCESS;
673
674 ReportError:
675 //
676 // Report error code before exiting
677 //
678 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
679 EFI_ERROR_CODE | EFI_ERROR_MINOR,
680 PcdGet32 (PcdStatusCodeValueRemoteConsoleError),
681 DevicePath
682 );
683
684 Error:
685 //
686 // Use the Stop() function to free all resources allocated in Start()
687 //
688 if (TerminalDevice != NULL) {
689
690 if (TerminalDevice->Handle != NULL) {
691 This->Stop (This, Controller, 1, &TerminalDevice->Handle);
692 } else {
693
694 if (TerminalDevice->TwoSecondTimeOut != NULL) {
695 gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);
696 }
697
698 if (TerminalDevice->SimpleInput.WaitForKey != NULL) {
699 gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);
700 }
701
702 if (TerminalDevice->SimpleInputEx.WaitForKeyEx != NULL) {
703 gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);
704 }
705
706 TerminalFreeNotifyList (&TerminalDevice->NotifyList);
707
708 if (TerminalDevice->ControllerNameTable != NULL) {
709 FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
710 }
711
712 if (TerminalDevice->DevicePath != NULL) {
713 FreePool (TerminalDevice->DevicePath);
714 }
715
716 FreePool (TerminalDevice);
717 }
718 }
719
720 if (DefaultNode != NULL) {
721 FreePool (DefaultNode);
722 }
723
724 This->Stop (This, Controller, 0, NULL);
725
726 return Status;
727 }
728
729
730 /**
731 Stop a device controller.
732
733 @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
734 instance.
735 @param Controller A handle to the device being stopped.
736 @param NumberOfChildren The number of child device handles in
737 ChildHandleBuffer.
738 @param ChildHandleBuffer An array of child handles to be freed.
739
740 @retval EFI_SUCCESS Operation successful.
741 @retval EFI_DEVICE_ERROR Devices error.
742
743 **/
744 EFI_STATUS
745 EFIAPI
746 TerminalDriverBindingStop (
747 IN EFI_DRIVER_BINDING_PROTOCOL *This,
748 IN EFI_HANDLE Controller,
749 IN UINTN NumberOfChildren,
750 IN EFI_HANDLE *ChildHandleBuffer
751 )
752 {
753 EFI_STATUS Status;
754 UINTN Index;
755 BOOLEAN AllChildrenStopped;
756 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;
757 TERMINAL_DEV *TerminalDevice;
758 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
759 EFI_SERIAL_IO_PROTOCOL *SerialIo;
760 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
761
762 Status = gBS->HandleProtocol (
763 Controller,
764 &gEfiDevicePathProtocolGuid,
765 (VOID **) &DevicePath
766 );
767 if (EFI_ERROR (Status)) {
768 return Status;
769 }
770
771 //
772 // Complete all outstanding transactions to Controller.
773 // Don't allow any new transaction to Controller to be started.
774 //
775 if (NumberOfChildren == 0) {
776 //
777 // Close the bus driver
778 //
779 Status = gBS->OpenProtocol (
780 Controller,
781 &gEfiCallerIdGuid,
782 (VOID **) &ParentDevicePath,
783 This->DriverBindingHandle,
784 Controller,
785 EFI_OPEN_PROTOCOL_GET_PROTOCOL
786 );
787 if (!EFI_ERROR (Status)) {
788 //
789 // Remove Parent Device Path from
790 // the Console Device Environment Variables
791 //
792 TerminalRemoveConsoleDevVariable (L"ConInDev", ParentDevicePath);
793 TerminalRemoveConsoleDevVariable (L"ConOutDev", ParentDevicePath);
794 TerminalRemoveConsoleDevVariable (L"ErrOutDev", ParentDevicePath);
795
796 //
797 // Uninstall the Terminal Driver's GUID Tag from the Serial controller
798 //
799 Status = gBS->UninstallMultipleProtocolInterfaces (
800 Controller,
801 &gEfiCallerIdGuid,
802 ParentDevicePath,
803 NULL
804 );
805
806 //
807 // Free the ParentDevicePath that was duplicated in Start()
808 //
809 if (!EFI_ERROR (Status)) {
810 FreePool (ParentDevicePath);
811 }
812 }
813
814 gBS->CloseProtocol (
815 Controller,
816 &gEfiSerialIoProtocolGuid,
817 This->DriverBindingHandle,
818 Controller
819 );
820
821 gBS->CloseProtocol (
822 Controller,
823 &gEfiDevicePathProtocolGuid,
824 This->DriverBindingHandle,
825 Controller
826 );
827
828 return EFI_SUCCESS;
829 }
830
831 AllChildrenStopped = TRUE;
832
833 for (Index = 0; Index < NumberOfChildren; Index++) {
834
835 Status = gBS->OpenProtocol (
836 ChildHandleBuffer[Index],
837 &gEfiSimpleTextOutProtocolGuid,
838 (VOID **) &SimpleTextOutput,
839 This->DriverBindingHandle,
840 ChildHandleBuffer[Index],
841 EFI_OPEN_PROTOCOL_GET_PROTOCOL
842 );
843 if (!EFI_ERROR (Status)) {
844
845 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);
846
847 gBS->CloseProtocol (
848 Controller,
849 &gEfiSerialIoProtocolGuid,
850 This->DriverBindingHandle,
851 ChildHandleBuffer[Index]
852 );
853
854 Status = gBS->UninstallMultipleProtocolInterfaces (
855 ChildHandleBuffer[Index],
856 &gEfiSimpleTextInProtocolGuid,
857 &TerminalDevice->SimpleInput,
858 &gEfiSimpleTextInputExProtocolGuid,
859 &TerminalDevice->SimpleInputEx,
860 &gEfiSimpleTextOutProtocolGuid,
861 &TerminalDevice->SimpleTextOutput,
862 &gEfiDevicePathProtocolGuid,
863 TerminalDevice->DevicePath,
864 NULL
865 );
866 if (EFI_ERROR (Status)) {
867 gBS->OpenProtocol (
868 Controller,
869 &gEfiSerialIoProtocolGuid,
870 (VOID **) &SerialIo,
871 This->DriverBindingHandle,
872 ChildHandleBuffer[Index],
873 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
874 );
875 } else {
876
877 if (TerminalDevice->ControllerNameTable != NULL) {
878 FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
879 }
880
881 Status = gBS->OpenProtocol (
882 ChildHandleBuffer[Index],
883 &gEfiHotPlugDeviceGuid,
884 NULL,
885 This->DriverBindingHandle,
886 Controller,
887 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
888 );
889 if (!EFI_ERROR (Status)) {
890 Status = gBS->UninstallMultipleProtocolInterfaces (
891 ChildHandleBuffer[Index],
892 &gEfiHotPlugDeviceGuid,
893 NULL,
894 NULL
895 );
896 } else {
897 Status = EFI_SUCCESS;
898 }
899
900 gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);
901 gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);
902 gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);
903 TerminalFreeNotifyList (&TerminalDevice->NotifyList);
904 FreePool (TerminalDevice->DevicePath);
905 FreePool (TerminalDevice);
906 }
907 }
908
909 if (EFI_ERROR (Status)) {
910 AllChildrenStopped = FALSE;
911 }
912 }
913
914 if (!AllChildrenStopped) {
915 return EFI_DEVICE_ERROR;
916 }
917
918 return EFI_SUCCESS;
919 }
920
921
922 /**
923
924 @param ListHead The list head
925
926 @retval EFI_SUCCESS Free the notify list successfully
927 @retval EFI_INVALID_PARAMETER ListHead is invalid.
928
929 **/
930 EFI_STATUS
931 TerminalFreeNotifyList (
932 IN OUT LIST_ENTRY *ListHead
933 )
934 {
935 TERMINAL_CONSOLE_IN_EX_NOTIFY *NotifyNode;
936
937 if (ListHead == NULL) {
938 return EFI_INVALID_PARAMETER;
939 }
940 while (!IsListEmpty (ListHead)) {
941 NotifyNode = CR (
942 ListHead->ForwardLink,
943 TERMINAL_CONSOLE_IN_EX_NOTIFY,
944 NotifyEntry,
945 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
946 );
947 RemoveEntryList (ListHead->ForwardLink);
948 gBS->FreePool (NotifyNode);
949 }
950
951 return EFI_SUCCESS;
952 }
953
954
955
956 VOID
957 TerminalUpdateConsoleDevVariable (
958 IN CHAR16 *VariableName,
959 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
960 )
961 {
962 EFI_STATUS Status;
963 UINTN VariableSize;
964 UINT8 TerminalType;
965 EFI_DEVICE_PATH_PROTOCOL *Variable;
966 EFI_DEVICE_PATH_PROTOCOL *NewVariable;
967 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
968
969 Variable = NULL;
970
971 //
972 // Get global variable and its size according to the name given.
973 //
974 Variable = TerminalGetVariableAndSize (
975 VariableName,
976 &gEfiGlobalVariableGuid,
977 &VariableSize
978 );
979 //
980 // Append terminal device path onto the variable.
981 //
982 for (TerminalType = PCANSITYPE; TerminalType <= VTUTF8TYPE; TerminalType++) {
983 SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);
984 NewVariable = AppendDevicePathInstance (Variable, TempDevicePath);
985 if (Variable != NULL) {
986 FreePool (Variable);
987 }
988
989 if (TempDevicePath != NULL) {
990 FreePool (TempDevicePath);
991 }
992
993 Variable = NewVariable;
994 }
995
996 VariableSize = GetDevicePathSize (Variable);
997
998 Status = gRT->SetVariable (
999 VariableName,
1000 &gEfiGlobalVariableGuid,
1001 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
1002 VariableSize,
1003 Variable
1004 );
1005 ASSERT_EFI_ERROR (Status);
1006 FreePool (Variable);
1007
1008 return ;
1009 }
1010
1011
1012 /**
1013 Remove console device variable.
1014
1015 @param VariableName A pointer to the variable name.
1016 @param ParentDevicePath A pointer to the parent device path.
1017
1018 @return None.
1019
1020 **/
1021 VOID
1022 TerminalRemoveConsoleDevVariable (
1023 IN CHAR16 *VariableName,
1024 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
1025 )
1026 {
1027 EFI_STATUS Status;
1028 BOOLEAN FoundOne;
1029 BOOLEAN Match;
1030 UINTN VariableSize;
1031 UINTN InstanceSize;
1032 UINT8 TerminalType;
1033 EFI_DEVICE_PATH_PROTOCOL *Instance;
1034 EFI_DEVICE_PATH_PROTOCOL *Variable;
1035 EFI_DEVICE_PATH_PROTOCOL *OriginalVariable;
1036 EFI_DEVICE_PATH_PROTOCOL *NewVariable;
1037 EFI_DEVICE_PATH_PROTOCOL *SavedNewVariable;
1038 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1039
1040 Variable = NULL;
1041 Instance = NULL;
1042
1043 //
1044 // Get global variable and its size according to the name given.
1045 //
1046 Variable = TerminalGetVariableAndSize (
1047 VariableName,
1048 &gEfiGlobalVariableGuid,
1049 &VariableSize
1050 );
1051 if (Variable == NULL) {
1052 return ;
1053 }
1054
1055 FoundOne = FALSE;
1056 OriginalVariable = Variable;
1057 NewVariable = NULL;
1058
1059 //
1060 // Get first device path instance from Variable
1061 //
1062 Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);
1063 if (Instance == NULL) {
1064 FreePool (OriginalVariable);
1065 return ;
1066 }
1067 //
1068 // Loop through all the device path instances of Variable
1069 //
1070 do {
1071 //
1072 // Loop through all the terminal types that this driver supports
1073 //
1074 Match = FALSE;
1075 for (TerminalType = PCANSITYPE; TerminalType <= VTUTF8TYPE; TerminalType++) {
1076
1077 SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);
1078
1079 //
1080 // Compare the genterated device path to the current device path instance
1081 //
1082 if (TempDevicePath != NULL) {
1083 if (CompareMem (Instance, TempDevicePath, InstanceSize) == 0) {
1084 Match = TRUE;
1085 FoundOne = TRUE;
1086 }
1087
1088 FreePool (TempDevicePath);
1089 }
1090 }
1091 //
1092 // If a match was not found, then keep the current device path instance
1093 //
1094 if (!Match) {
1095 SavedNewVariable = NewVariable;
1096 NewVariable = AppendDevicePathInstance (NewVariable, Instance);
1097 if (SavedNewVariable != NULL) {
1098 FreePool (SavedNewVariable);
1099 }
1100 }
1101 //
1102 // Get next device path instance from Variable
1103 //
1104 FreePool (Instance);
1105 Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);
1106 } while (Instance != NULL);
1107
1108 FreePool (OriginalVariable);
1109
1110 if (FoundOne) {
1111 VariableSize = GetDevicePathSize (NewVariable);
1112
1113 Status = gRT->SetVariable (
1114 VariableName,
1115 &gEfiGlobalVariableGuid,
1116 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
1117 VariableSize,
1118 NewVariable
1119 );
1120 ASSERT_EFI_ERROR (Status);
1121 }
1122
1123 if (NewVariable != NULL) {
1124 FreePool (NewVariable);
1125 }
1126
1127 return ;
1128 }
1129
1130
1131 /**
1132 Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
1133 buffer, and the size of the buffer. On failure return NULL.
1134
1135 @param Name String part of EFI variable name
1136 @param VendorGuid GUID part of EFI variable name
1137 @param VariableSize Returns the size of the EFI variable that was read
1138
1139 @return Dynamically allocated memory that contains a copy of the EFI variable.
1140 @return Caller is repsoncible freeing the buffer.
1141 @retval NULL Variable was not read
1142
1143 **/
1144 VOID *
1145 TerminalGetVariableAndSize (
1146 IN CHAR16 *Name,
1147 IN EFI_GUID *VendorGuid,
1148 OUT UINTN *VariableSize
1149 )
1150 {
1151 EFI_STATUS Status;
1152 UINTN BufferSize;
1153 VOID *Buffer;
1154
1155 Buffer = NULL;
1156
1157 //
1158 // Pass in a small size buffer to find the actual variable size.
1159 //
1160 BufferSize = 1;
1161 Buffer = AllocatePool (BufferSize);
1162 if (Buffer == NULL) {
1163 *VariableSize = 0;
1164 return NULL;
1165 }
1166
1167 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
1168
1169 if (Status == EFI_SUCCESS) {
1170 *VariableSize = BufferSize;
1171 return Buffer;
1172
1173 } else if (Status == EFI_BUFFER_TOO_SMALL) {
1174 //
1175 // Allocate the buffer to return
1176 //
1177 FreePool (Buffer);
1178 Buffer = AllocatePool (BufferSize);
1179 if (Buffer == NULL) {
1180 *VariableSize = 0;
1181 return NULL;
1182 }
1183 //
1184 // Read variable into the allocated buffer.
1185 //
1186 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
1187 if (EFI_ERROR (Status)) {
1188 BufferSize = 0;
1189 FreePool (Buffer);
1190 Buffer = NULL;
1191 }
1192 } else {
1193 //
1194 // Variable not found or other errors met.
1195 //
1196 BufferSize = 0;
1197 FreePool (Buffer);
1198 Buffer = NULL;
1199 }
1200
1201 *VariableSize = BufferSize;
1202 return Buffer;
1203 }
1204
1205 EFI_STATUS
1206 SetTerminalDevicePath (
1207 IN UINT8 TerminalType,
1208 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
1209 OUT EFI_DEVICE_PATH_PROTOCOL **TerminalDevicePath
1210 )
1211 {
1212 VENDOR_DEVICE_PATH Node;
1213
1214 *TerminalDevicePath = NULL;
1215 Node.Header.Type = MESSAGING_DEVICE_PATH;
1216 Node.Header.SubType = MSG_VENDOR_DP;
1217
1218 //
1219 // generate terminal device path node according to terminal type.
1220 //
1221 switch (TerminalType) {
1222
1223 case PCANSITYPE:
1224 CopyMem (
1225 &Node.Guid,
1226 &gEfiPcAnsiGuid,
1227 sizeof (EFI_GUID)
1228 );
1229 break;
1230
1231 case VT100TYPE:
1232 CopyMem (
1233 &Node.Guid,
1234 &gEfiVT100Guid,
1235 sizeof (EFI_GUID)
1236 );
1237 break;
1238
1239 case VT100PLUSTYPE:
1240 CopyMem (
1241 &Node.Guid,
1242 &gEfiVT100PlusGuid,
1243 sizeof (EFI_GUID)
1244 );
1245 break;
1246
1247 case VTUTF8TYPE:
1248 CopyMem (
1249 &Node.Guid,
1250 &gEfiVTUTF8Guid,
1251 sizeof (EFI_GUID)
1252 );
1253 break;
1254
1255 default:
1256 return EFI_UNSUPPORTED;
1257 break;
1258 }
1259
1260 SetDevicePathNodeLength (
1261 &Node.Header,
1262 sizeof (VENDOR_DEVICE_PATH)
1263 );
1264 //
1265 // append the terminal node onto parent device path
1266 // to generate a complete terminal device path.
1267 //
1268 *TerminalDevicePath = AppendDevicePathNode (
1269 ParentDevicePath,
1270 (EFI_DEVICE_PATH_PROTOCOL *) &Node
1271 );
1272 if (*TerminalDevicePath == NULL) {
1273 return EFI_OUT_OF_RESOURCES;
1274 }
1275
1276 return EFI_SUCCESS;
1277 }
1278
1279 VOID
1280 InitializeRawFiFo (
1281 IN TERMINAL_DEV *TerminalDevice
1282 )
1283 {
1284 //
1285 // Make the raw fifo empty.
1286 //
1287 TerminalDevice->RawFiFo.Head = TerminalDevice->RawFiFo.Tail;
1288 }
1289
1290 VOID
1291 InitializeUnicodeFiFo (
1292 IN TERMINAL_DEV *TerminalDevice
1293 )
1294 {
1295 //
1296 // Make the unicode fifo empty
1297 //
1298 TerminalDevice->UnicodeFiFo.Head = TerminalDevice->UnicodeFiFo.Tail;
1299 }
1300
1301 VOID
1302 InitializeEfiKeyFiFo (
1303 IN TERMINAL_DEV *TerminalDevice
1304 )
1305 {
1306 //
1307 // Make the efi key fifo empty
1308 //
1309 TerminalDevice->EfiKeyFiFo.Head = TerminalDevice->EfiKeyFiFo.Tail;
1310 }
1311
1312
1313 /**
1314 The user Entry Point for module Terminal. The user code starts with this function.
1315
1316 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1317 @param[in] SystemTable A pointer to the EFI System Table.
1318
1319 @retval EFI_SUCCESS The entry point is executed successfully.
1320 @retval other Some error occurs when executing this entry point.
1321
1322 **/
1323 EFI_STATUS
1324 EFIAPI
1325 InitializeTerminal(
1326 IN EFI_HANDLE ImageHandle,
1327 IN EFI_SYSTEM_TABLE *SystemTable
1328 )
1329 {
1330 EFI_STATUS Status;
1331
1332 //
1333 // Install driver model protocol(s).
1334 //
1335 Status = EfiLibInstallDriverBindingComponentName2 (
1336 ImageHandle,
1337 SystemTable,
1338 &gTerminalDriverBinding,
1339 ImageHandle,
1340 &gTerminalComponentName,
1341 &gTerminalComponentName2
1342 );
1343 ASSERT_EFI_ERROR (Status);
1344
1345
1346 return Status;
1347 }