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