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