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