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