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