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