]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
Fix the terminal driver to call hotkey callback even no one is calling ReadKeyStroke
[mirror_edk2.git] / MdeModulePkg / Universal / Console / TerminalDxe / Terminal.c
CommitLineData
fb0b259e 1/** @file\r
11baadb6 2 Produces Simple Text Input Protocol, Simple Text Input Extended Protocol and\r
fb0b259e 3 Simple Text Output Protocol upon Serial IO Protocol.\r
95276127 4\r
f0368006 5Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
e5eed7d3 6This program and the accompanying materials\r
95276127 7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
fb0b259e 14**/\r
95276127 15\r
16\r
95276127 17#include "Terminal.h"\r
18\r
95276127 19//\r
20// Globals\r
21//\r
22EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding = {\r
23 TerminalDriverBindingSupported,\r
24 TerminalDriverBindingStart,\r
25 TerminalDriverBindingStop,\r
26 0xa,\r
27 NULL,\r
28 NULL\r
29};\r
30\r
31\r
6b88ceec
A
32EFI_GUID *gTerminalType[] = {\r
33 &gEfiPcAnsiGuid,\r
34 &gEfiVT100Guid,\r
35 &gEfiVT100PlusGuid,\r
36 &gEfiVTUTF8Guid\r
37};\r
38\r
39\r
204ba917 40TERMINAL_DEV mTerminalDevTemplate = {\r
6b88ceec
A
41 TERMINAL_DEV_SIGNATURE,\r
42 NULL,\r
43 0,\r
44 NULL,\r
45 NULL,\r
46 { // SimpleTextInput\r
47 TerminalConInReset,\r
48 TerminalConInReadKeyStroke,\r
49 NULL\r
50 },\r
51 { // SimpleTextOutput\r
52 TerminalConOutReset,\r
53 TerminalConOutOutputString,\r
54 TerminalConOutTestString,\r
55 TerminalConOutQueryMode,\r
56 TerminalConOutSetMode,\r
57 TerminalConOutSetAttribute,\r
58 TerminalConOutClearScreen,\r
59 TerminalConOutSetCursorPosition,\r
60 TerminalConOutEnableCursor,\r
61 NULL\r
62 },\r
63 { // SimpleTextOutputMode\r
64 1, // MaxMode\r
11baadb6 65 0, // Mode\r
6b88ceec
A
66 EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK), // Attribute\r
67 0, // CursorColumn\r
68 0, // CursorRow\r
69 TRUE // CursorVisible\r
70 },\r
11baadb6 71 0, // SerialInTimeOut\r
5c998646 72\r
73 NULL, // RawFifo\r
74 NULL, // UnicodeFiFo\r
75 NULL, // EfiKeyFiFo\r
76\r
6b88ceec 77 NULL, // ControllerNameTable\r
f0368006 78 NULL, // TimerEvent\r
11baadb6 79 NULL, // TwoSecondTimeOut\r
6b88ceec
A
80 INPUT_STATE_DEFAULT,\r
81 RESET_STATE_DEFAULT,\r
66aa04e4 82 FALSE,\r
83 { // SimpleTextInputEx\r
84 TerminalConInResetEx,\r
85 TerminalConInReadKeyStrokeEx,\r
86 NULL,\r
87 TerminalConInSetState,\r
88 TerminalConInRegisterKeyNotify,\r
89 TerminalConInUnregisterKeyNotify,\r
90 },\r
11baadb6 91 { // NotifyList\r
66aa04e4 92 NULL,\r
93 NULL,\r
94 }\r
6b88ceec
A
95};\r
96\r
8fd98315 97/**\r
677fdb90 98 Test to see if this driver supports Controller.\r
8fd98315 99\r
100 @param This Protocol instance pointer.\r
ab76200c 101 @param Controller Handle of device to test\r
8fd98315 102 @param RemainingDevicePath Optional parameter use to pick a specific child\r
103 device to start.\r
104\r
ab76200c 105 @retval EFI_SUCCESS This driver supports this device.\r
106 @retval EFI_ALREADY_STARTED This driver is already running on this device.\r
107 @retval other This driver does not support this device.\r
6b88ceec 108\r
8fd98315 109**/\r
95276127 110EFI_STATUS\r
111EFIAPI\r
112TerminalDriverBindingSupported (\r
113 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
114 IN EFI_HANDLE Controller,\r
115 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
116 )\r
117{\r
118 EFI_STATUS Status;\r
119 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
120 EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
121 VENDOR_DEVICE_PATH *Node;\r
122\r
123 //\r
124 // If remaining device path is not NULL, then make sure it is a\r
125 // device path that describes a terminal communications protocol.\r
126 //\r
127 if (RemainingDevicePath != NULL) {\r
95276127 128 //\r
e3dcffcc 129 // Check if RemainingDevicePath is the End of Device Path Node,\r
af4a6385 130 // if yes, go on checking other conditions\r
95276127 131 //\r
af4a6385 132 if (!IsDevicePathEnd (RemainingDevicePath)) {\r
133 //\r
134 // If RemainingDevicePath isn't the End of Device Path Node,\r
135 // check its validation\r
136 //\r
137 Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;\r
e3dcffcc 138\r
af4a6385 139 if (Node->Header.Type != MESSAGING_DEVICE_PATH ||\r
140 Node->Header.SubType != MSG_VENDOR_DP ||\r
141 DevicePathNodeLength(&Node->Header) != sizeof(VENDOR_DEVICE_PATH)) {\r
e3dcffcc 142\r
af4a6385 143 return EFI_UNSUPPORTED;\r
e3dcffcc 144\r
af4a6385 145 }\r
146 //\r
147 // only supports PC ANSI, VT100, VT100+ and VT-UTF8 terminal types\r
148 //\r
149 if (!CompareGuid (&Node->Guid, &gEfiPcAnsiGuid) &&\r
150 !CompareGuid (&Node->Guid, &gEfiVT100Guid) &&\r
151 !CompareGuid (&Node->Guid, &gEfiVT100PlusGuid) &&\r
152 !CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {\r
e3dcffcc 153\r
af4a6385 154 return EFI_UNSUPPORTED;\r
155 }\r
95276127 156 }\r
157 }\r
158 //\r
159 // Open the IO Abstraction(s) needed to perform the supported test\r
af4a6385 160 // The Controller must support the Serial I/O Protocol.\r
161 // This driver is a bus driver with at most 1 child device, so it is\r
162 // ok for it to be already started.\r
95276127 163 //\r
164 Status = gBS->OpenProtocol (\r
165 Controller,\r
af4a6385 166 &gEfiSerialIoProtocolGuid,\r
167 (VOID **) &SerialIo,\r
95276127 168 This->DriverBindingHandle,\r
169 Controller,\r
170 EFI_OPEN_PROTOCOL_BY_DRIVER\r
171 );\r
172 if (Status == EFI_ALREADY_STARTED) {\r
173 return EFI_SUCCESS;\r
174 }\r
175\r
176 if (EFI_ERROR (Status)) {\r
177 return Status;\r
178 }\r
179\r
af4a6385 180 //\r
181 // Close the I/O Abstraction(s) used to perform the supported test\r
182 //\r
95276127 183 gBS->CloseProtocol (\r
184 Controller,\r
af4a6385 185 &gEfiSerialIoProtocolGuid,\r
95276127 186 This->DriverBindingHandle,\r
187 Controller\r
188 );\r
189\r
190 //\r
af4a6385 191 // Open the EFI Device Path protocol needed to perform the supported test\r
95276127 192 //\r
193 Status = gBS->OpenProtocol (\r
194 Controller,\r
af4a6385 195 &gEfiDevicePathProtocolGuid,\r
196 (VOID **) &ParentDevicePath,\r
95276127 197 This->DriverBindingHandle,\r
198 Controller,\r
199 EFI_OPEN_PROTOCOL_BY_DRIVER\r
200 );\r
201 if (Status == EFI_ALREADY_STARTED) {\r
202 return EFI_SUCCESS;\r
203 }\r
204\r
205 if (EFI_ERROR (Status)) {\r
206 return Status;\r
207 }\r
af4a6385 208\r
95276127 209 //\r
af4a6385 210 // Close protocol, don't use device path protocol in the Support() function\r
95276127 211 //\r
212 gBS->CloseProtocol (\r
213 Controller,\r
af4a6385 214 &gEfiDevicePathProtocolGuid,\r
95276127 215 This->DriverBindingHandle,\r
216 Controller\r
217 );\r
218\r
219 return Status;\r
220}\r
221\r
e3dcffcc 222/**\r
223 Build the terminal device path for the child device according to the\r
224 terminal type.\r
225\r
226 @param ParentDevicePath Parent device path.\r
227 @param RemainingDevicePath A specific child device.\r
228\r
229 @return The child device path built.\r
230\r
231**/\r
232EFI_DEVICE_PATH_PROTOCOL*\r
233EFIAPI\r
234BuildTerminalDevpath (\r
235 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
236 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
237 )\r
238{\r
239 EFI_DEVICE_PATH_PROTOCOL *TerminalDevicePath;\r
240 UINT8 TerminalType;\r
241 VENDOR_DEVICE_PATH *Node;\r
242 EFI_STATUS Status;\r
243\r
244 TerminalDevicePath = NULL;\r
245 TerminalType = PCANSITYPE;\r
246\r
247 //\r
248 // Use the RemainingDevicePath to determine the terminal type\r
249 //\r
250 Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;\r
251 if (Node == NULL) {\r
252 TerminalType = PCANSITYPE;\r
253\r
254 } else if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) {\r
255\r
256 TerminalType = PCANSITYPE;\r
257\r
258 } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) {\r
259\r
260 TerminalType = VT100TYPE;\r
261\r
262 } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) {\r
263\r
264 TerminalType = VT100PLUSTYPE;\r
265\r
266 } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {\r
267\r
268 TerminalType = VTUTF8TYPE;\r
269\r
270 } else {\r
271 return NULL;\r
272 }\r
273\r
274 //\r
275 // Build the device path for the child device\r
276 //\r
277 Status = SetTerminalDevicePath (\r
278 TerminalType,\r
279 ParentDevicePath,\r
280 &TerminalDevicePath\r
281 );\r
282 if (EFI_ERROR (Status)) {\r
283 return NULL;\r
284 }\r
285 return TerminalDevicePath;\r
286}\r
287\r
288/**\r
289 Compare a device path data structure to that of all the nodes of a\r
290 second device path instance.\r
291\r
292 @param Multi A pointer to a multi-instance device path data structure.\r
293 @param Single A pointer to a single-instance device path data structure.\r
294\r
295 @retval TRUE If the Single is contained within Multi.\r
296 @retval FALSE The Single is not match within Multi.\r
297\r
298**/\r
299BOOLEAN\r
300MatchDevicePaths (\r
301 IN EFI_DEVICE_PATH_PROTOCOL *Multi,\r
302 IN EFI_DEVICE_PATH_PROTOCOL *Single\r
303 )\r
304{\r
305 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
306 EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;\r
307 UINTN Size;\r
308\r
309 DevicePath = Multi;\r
310 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);\r
311 //\r
312 // Search for the match of 'Single' in 'Multi'\r
313 //\r
314 while (DevicePathInst != NULL) {\r
315 //\r
316 // If the single device path is found in multiple device paths,\r
317 // return success\r
318 //\r
319 if (CompareMem (Single, DevicePathInst, Size) == 0) {\r
320 FreePool (DevicePathInst);\r
321 return TRUE;\r
322 }\r
323\r
324 FreePool (DevicePathInst);\r
325 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);\r
326 }\r
327\r
328 return FALSE;\r
329}\r
330\r
331/**\r
332 Check whether the terminal device path is in the global variable.\r
333\r
334 @param VariableName Pointer to one global variable.\r
335 @param TerminalDevicePath Pointer to the terminal device's device path.\r
336\r
337 @retval TRUE The devcie is in the global variable.\r
338 @retval FALSE The devcie is not in the global variable.\r
339\r
340**/\r
341BOOLEAN\r
342IsTerminalInConsoleVariable (\r
343 IN CHAR16 *VariableName,\r
344 IN EFI_DEVICE_PATH_PROTOCOL *TerminalDevicePath\r
345 )\r
346{\r
347 EFI_DEVICE_PATH_PROTOCOL *Variable;\r
348 BOOLEAN ReturnFlag;\r
349\r
350 //\r
351 // Get global variable and its size according to the name given.\r
352 //\r
353 Variable = GetEfiGlobalVariable (VariableName);\r
354 if (Variable == NULL) {\r
355 return FALSE;\r
356 }\r
357\r
358 //\r
359 // Check whether the terminal device path is one of the variable instances.\r
360 //\r
361 ReturnFlag = MatchDevicePaths (Variable, TerminalDevicePath);\r
362\r
363 FreePool (Variable);\r
364\r
365 return ReturnFlag;\r
366}\r
367\r
368/**\r
369 Free notify functions list.\r
370\r
371 @param ListHead The list head\r
372\r
373 @retval EFI_SUCCESS Free the notify list successfully.\r
374 @retval EFI_INVALID_PARAMETER ListHead is NULL.\r
375\r
376**/\r
377EFI_STATUS\r
378TerminalFreeNotifyList (\r
379 IN OUT LIST_ENTRY *ListHead\r
380 )\r
381{\r
382 TERMINAL_CONSOLE_IN_EX_NOTIFY *NotifyNode;\r
383\r
384 if (ListHead == NULL) {\r
385 return EFI_INVALID_PARAMETER;\r
386 }\r
387 while (!IsListEmpty (ListHead)) {\r
388 NotifyNode = CR (\r
389 ListHead->ForwardLink,\r
390 TERMINAL_CONSOLE_IN_EX_NOTIFY,\r
391 NotifyEntry,\r
392 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
393 );\r
394 RemoveEntryList (ListHead->ForwardLink);\r
395 FreePool (NotifyNode);\r
396 }\r
397\r
398 return EFI_SUCCESS;\r
399}\r
400\r
401\r
e49ef433 402/**\r
ab76200c 403 Start this driver on Controller by opening a Serial IO protocol,\r
8fd98315 404 reading Device Path, and creating a child handle with a Simple Text In,\r
405 Simple Text In Ex and Simple Text Out protocol, and device path protocol.\r
406 And store Console Device Environment Variables.\r
e49ef433 407\r
8fd98315 408 @param This Protocol instance pointer.\r
ab76200c 409 @param Controller Handle of device to bind driver to\r
8fd98315 410 @param RemainingDevicePath Optional parameter use to pick a specific child\r
411 device to start.\r
e49ef433 412\r
ab76200c 413 @retval EFI_SUCCESS This driver is added to Controller.\r
414 @retval EFI_ALREADY_STARTED This driver is already running on Controller.\r
415 @retval other This driver does not support this device.\r
e49ef433 416\r
417**/\r
95276127 418EFI_STATUS\r
419EFIAPI\r
420TerminalDriverBindingStart (\r
421 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
422 IN EFI_HANDLE Controller,\r
423 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
424 )\r
95276127 425{\r
426 EFI_STATUS Status;\r
427 EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
428 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
429 VENDOR_DEVICE_PATH *Node;\r
430 VENDOR_DEVICE_PATH *DefaultNode;\r
431 EFI_SERIAL_IO_MODE *Mode;\r
432 UINTN SerialInTimeOut;\r
433 TERMINAL_DEV *TerminalDevice;\r
434 UINT8 TerminalType;\r
435 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;\r
436 UINTN EntryCount;\r
437 UINTN Index;\r
438 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
c4f9201e 439 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;\r
e3dcffcc 440 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextInput;\r
441 BOOLEAN ConInSelected;\r
442 BOOLEAN ConOutSelected;\r
443 BOOLEAN NullRemaining;\r
444 BOOLEAN SimTxtInInstalled;\r
445 BOOLEAN SimTxtOutInstalled;\r
446 BOOLEAN FirstEnter;\r
447\r
448 TerminalDevice = NULL;\r
449 DefaultNode = NULL;\r
450 ConInSelected = FALSE;\r
451 ConOutSelected = FALSE;\r
452 NullRemaining = TRUE;\r
453 SimTxtInInstalled = FALSE;\r
454 SimTxtOutInstalled = FALSE;\r
455 FirstEnter = FALSE;\r
95276127 456 //\r
457 // Get the Device Path Protocol to build the device path of the child device\r
458 //\r
459 Status = gBS->OpenProtocol (\r
460 Controller,\r
461 &gEfiDevicePathProtocolGuid,\r
462 (VOID **) &ParentDevicePath,\r
463 This->DriverBindingHandle,\r
464 Controller,\r
465 EFI_OPEN_PROTOCOL_BY_DRIVER\r
466 );\r
467 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
468 return Status;\r
469 }\r
95276127 470\r
471 //\r
472 // Open the Serial I/O Protocol BY_DRIVER. It might already be started.\r
473 //\r
474 Status = gBS->OpenProtocol (\r
475 Controller,\r
476 &gEfiSerialIoProtocolGuid,\r
477 (VOID **) &SerialIo,\r
478 This->DriverBindingHandle,\r
479 Controller,\r
480 EFI_OPEN_PROTOCOL_BY_DRIVER\r
481 );\r
482 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
483 return Status;\r
484 }\r
485\r
486 if (Status != EFI_ALREADY_STARTED) {\r
487 //\r
e3dcffcc 488 // the serial I/O protocol never be opened before, it is the first\r
489 // time to start the serial Io controller\r
95276127 490 //\r
e3dcffcc 491 FirstEnter = TRUE;\r
95276127 492 }\r
e3dcffcc 493\r
95276127 494 //\r
e3dcffcc 495 // Serial I/O is not already open by this driver, then tag the handle\r
496 // with the Terminal Driver GUID and update the ConInDev, ConOutDev, and\r
497 // StdErrDev variables with the list of possible terminal types on this\r
498 // serial port.\r
95276127 499 //\r
e3dcffcc 500 Status = gBS->OpenProtocol (\r
95276127 501 Controller,\r
e3dcffcc 502 &gEfiCallerIdGuid,\r
503 NULL,\r
504 This->DriverBindingHandle,\r
505 Controller,\r
506 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
95276127 507 );\r
e3dcffcc 508 if (EFI_ERROR (Status)) {\r
509 Status = gBS->InstallMultipleProtocolInterfaces (\r
510 &Controller,\r
511 &gEfiCallerIdGuid,\r
512 DuplicateDevicePath (ParentDevicePath),\r
513 NULL\r
514 );\r
515 if (EFI_ERROR (Status)) {\r
516 goto Error;\r
95276127 517 }\r
518\r
e3dcffcc 519 if (!IsHotPlugDevice (ParentDevicePath)) {\r
520 //\r
521 // if the serial device is a hot plug device, do not update the\r
522 // ConInDev, ConOutDev, and StdErrDev variables.\r
523 //\r
524 TerminalUpdateConsoleDevVariable (L"ConInDev", ParentDevicePath);\r
525 TerminalUpdateConsoleDevVariable (L"ConOutDev", ParentDevicePath);\r
526 TerminalUpdateConsoleDevVariable (L"ErrOutDev", ParentDevicePath);\r
95276127 527 }\r
528 }\r
e3dcffcc 529\r
530 //\r
531 // Check the requirement for the SimpleTxtIn and SimpleTxtOut protocols\r
95276127 532 //\r
e3dcffcc 533 // Simple In/Out Protocol will not be installed onto the handle if the\r
534 // device path to the handle is not present in the ConIn/ConOut\r
535 // environment variable. But If RemainingDevicePath is NULL, then always\r
536 // produce both Simple In and Simple Text Output Protocols. This is required\r
537 // for the connect all sequences to make sure all possible consoles are\r
538 // produced no matter what the current values of ConIn, ConOut, or StdErr are.\r
95276127 539 //\r
540 if (RemainingDevicePath == NULL) {\r
e3dcffcc 541 NullRemaining = TRUE;\r
542 }\r
543\r
544 DevicePath = BuildTerminalDevpath (ParentDevicePath, RemainingDevicePath);\r
545 if (DevicePath != NULL) {\r
546 ConInSelected = IsTerminalInConsoleVariable (L"ConIn", DevicePath);\r
547 ConOutSelected = IsTerminalInConsoleVariable (L"ConOut", DevicePath);\r
548 FreePool (DevicePath);\r
549 } else {\r
550 goto Error;\r
551 }\r
552 //\r
553 // Not create the child terminal handle if both Simple In/In Ex and\r
554 // Simple text Out protocols are not required to be published\r
555 //\r
556 if ((!ConInSelected)&&(!ConOutSelected)&&(!NullRemaining)) {\r
557 goto Error;\r
558 }\r
559\r
560 //\r
561 // create the child terminal handle during first entry\r
562 //\r
563 if (FirstEnter) {\r
564 //\r
565 // First enther the start funciton\r
566 //\r
567 FirstEnter = FALSE;\r
568 //\r
569 // Make sure a child handle does not already exist. This driver can only\r
570 // produce one child per serial port.\r
571 //\r
572 Status = gBS->OpenProtocolInformation (\r
573 Controller,\r
574 &gEfiSerialIoProtocolGuid,\r
575 &OpenInfoBuffer,\r
576 &EntryCount\r
577 );\r
578 if (!EFI_ERROR (Status)) {\r
579 Status = EFI_SUCCESS;\r
580 for (Index = 0; Index < EntryCount; Index++) {\r
581 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {\r
582 Status = EFI_ALREADY_STARTED;\r
583 }\r
584 }\r
585\r
586 FreePool (OpenInfoBuffer);\r
587 if (EFI_ERROR (Status)) {\r
588 goto Error;\r
589 }\r
590 }\r
591\r
592 //\r
593 // If RemainingDevicePath is NULL, then create default device path node\r
594 //\r
595 if (RemainingDevicePath == NULL) {\r
596 DefaultNode = AllocateZeroPool (sizeof (VENDOR_DEVICE_PATH));\r
597 if (DefaultNode == NULL) {\r
598 Status = EFI_OUT_OF_RESOURCES;\r
599 goto Error;\r
600 }\r
601\r
188e4e84 602 TerminalType = PcdGet8 (PcdDefaultTerminalType);\r
e3dcffcc 603 //\r
604 // Must be between PCANSITYPE (0) and VTUTF8TYPE (3)\r
605 //\r
606 ASSERT (TerminalType <= VTUTF8TYPE);\r
607\r
608 CopyMem (&DefaultNode->Guid, gTerminalType[TerminalType], sizeof (EFI_GUID));\r
609 RemainingDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) DefaultNode;\r
610 } else if (!IsDevicePathEnd (RemainingDevicePath)) {\r
611 //\r
612 // If RemainingDevicePath isn't the End of Device Path Node,\r
613 // Use the RemainingDevicePath to determine the terminal type\r
614 //\r
615 Node = (VENDOR_DEVICE_PATH *)RemainingDevicePath;\r
616 if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) {\r
617 TerminalType = PCANSITYPE;\r
618 } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) {\r
619 TerminalType = VT100TYPE;\r
620 } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) {\r
621 TerminalType = VT100PLUSTYPE;\r
622 } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {\r
623 TerminalType = VTUTF8TYPE;\r
624 } else {\r
625 goto Error;\r
626 }\r
627 } else {\r
628 //\r
629 // If RemainingDevicePath is the End of Device Path Node,\r
630 // skip enumerate any device and return EFI_SUCESSS\r
631 //\r
632 return EFI_SUCCESS;\r
633 }\r
634\r
635 //\r
636 // Initialize the Terminal Dev\r
637 //\r
638 TerminalDevice = AllocateCopyPool (sizeof (TERMINAL_DEV), &mTerminalDevTemplate);\r
639 if (TerminalDevice == NULL) {\r
95276127 640 Status = EFI_OUT_OF_RESOURCES;\r
641 goto Error;\r
642 }\r
643\r
e3dcffcc 644 TerminalDevice->TerminalType = TerminalType;\r
645 TerminalDevice->SerialIo = SerialIo;\r
646\r
647 InitializeListHead (&TerminalDevice->NotifyList);\r
648 Status = gBS->CreateEvent (\r
649 EVT_NOTIFY_WAIT,\r
650 TPL_NOTIFY,\r
651 TerminalConInWaitForKeyEx,\r
f0368006 652 TerminalDevice,\r
e3dcffcc 653 &TerminalDevice->SimpleInputEx.WaitForKeyEx\r
654 );\r
655 if (EFI_ERROR (Status)) {\r
656 goto Error;\r
657 }\r
658\r
659 Status = gBS->CreateEvent (\r
660 EVT_NOTIFY_WAIT,\r
661 TPL_NOTIFY,\r
662 TerminalConInWaitForKey,\r
f0368006 663 TerminalDevice,\r
e3dcffcc 664 &TerminalDevice->SimpleInput.WaitForKey\r
665 );\r
666 if (EFI_ERROR (Status)) {\r
667 goto Error;\r
668 }\r
8fd98315 669 //\r
e3dcffcc 670 // Allocates and initializes the FIFO buffer to be zero, used for accommodating\r
671 // the pre-read pending characters.\r
8fd98315 672 //\r
e3dcffcc 673 TerminalDevice->RawFiFo = AllocateZeroPool (sizeof (RAW_DATA_FIFO));\r
674 if (TerminalDevice->RawFiFo == NULL) {\r
675 goto Error;\r
676 }\r
677 TerminalDevice->UnicodeFiFo = AllocateZeroPool (sizeof (UNICODE_FIFO));\r
678 if (TerminalDevice->UnicodeFiFo == NULL) {\r
679 goto Error;\r
680 }\r
681 TerminalDevice->EfiKeyFiFo = AllocateZeroPool (sizeof (EFI_KEY_FIFO));\r
682 if (TerminalDevice->EfiKeyFiFo == NULL) {\r
683 goto Error;\r
684 }\r
95276127 685\r
6b88ceec 686 //\r
e3dcffcc 687 // Set the timeout value of serial buffer for\r
688 // keystroke response performance issue\r
6b88ceec 689 //\r
e3dcffcc 690 Mode = TerminalDevice->SerialIo->Mode;\r
691\r
692 SerialInTimeOut = 0;\r
693 if (Mode->BaudRate != 0) {\r
694 SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate;\r
695 }\r
696\r
697 Status = TerminalDevice->SerialIo->SetAttributes (\r
698 TerminalDevice->SerialIo,\r
699 Mode->BaudRate,\r
700 Mode->ReceiveFifoDepth,\r
701 (UINT32) SerialInTimeOut,\r
702 (EFI_PARITY_TYPE) (Mode->Parity),\r
703 (UINT8) Mode->DataBits,\r
704 (EFI_STOP_BITS_TYPE) (Mode->StopBits)\r
705 );\r
706 if (EFI_ERROR (Status)) {\r
707 //\r
708 // if set attributes operation fails, invalidate\r
709 // the value of SerialInTimeOut,thus make it\r
710 // inconsistent with the default timeout value\r
711 // of serial buffer. This will invoke the recalculation\r
712 // in the readkeystroke routine.\r
713 //\r
714 TerminalDevice->SerialInTimeOut = 0;\r
6b88ceec 715 } else {\r
e3dcffcc 716 TerminalDevice->SerialInTimeOut = SerialInTimeOut;\r
6b88ceec 717 }\r
af4a6385 718 //\r
e3dcffcc 719 // Set Simple Text Output Protocol from template.\r
720 //\r
721 SimpleTextOutput = CopyMem (\r
722 &TerminalDevice->SimpleTextOutput,\r
723 &mTerminalDevTemplate.SimpleTextOutput,\r
724 sizeof (mTerminalDevTemplate.SimpleTextOutput)\r
725 );\r
726 SimpleTextOutput->Mode = &TerminalDevice->SimpleTextOutputMode;\r
727\r
9875a3e3 728 TerminalDevice->SimpleTextOutputMode.MaxMode = TERMINAL_MAX_MODE;\r
e3dcffcc 729 //\r
730 // For terminal devices, cursor is always visible\r
731 //\r
732 TerminalDevice->SimpleTextOutputMode.CursorVisible = TRUE;\r
733 Status = TerminalConOutSetAttribute (\r
734 SimpleTextOutput,\r
735 EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)\r
736 );\r
737 if (EFI_ERROR (Status)) {\r
738 goto ReportError;\r
739 }\r
6b88ceec 740\r
e3dcffcc 741 //\r
742 // Build the component name for the child device\r
743 //\r
744 TerminalDevice->ControllerNameTable = NULL;\r
745 switch (TerminalDevice->TerminalType) {\r
746 case PCANSITYPE:\r
747 AddUnicodeString2 (\r
748 "eng",\r
749 gTerminalComponentName.SupportedLanguages,\r
750 &TerminalDevice->ControllerNameTable,\r
751 (CHAR16 *)L"PC-ANSI Serial Console",\r
752 TRUE\r
753 );\r
754 AddUnicodeString2 (\r
755 "en",\r
756 gTerminalComponentName2.SupportedLanguages,\r
757 &TerminalDevice->ControllerNameTable,\r
758 (CHAR16 *)L"PC-ANSI Serial Console",\r
759 FALSE\r
760 );\r
95276127 761\r
e3dcffcc 762 break;\r
66aa04e4 763\r
e3dcffcc 764 case VT100TYPE:\r
765 AddUnicodeString2 (\r
766 "eng",\r
767 gTerminalComponentName.SupportedLanguages,\r
768 &TerminalDevice->ControllerNameTable,\r
769 (CHAR16 *)L"VT-100 Serial Console",\r
770 TRUE\r
771 );\r
772 AddUnicodeString2 (\r
773 "en",\r
774 gTerminalComponentName2.SupportedLanguages,\r
775 &TerminalDevice->ControllerNameTable,\r
776 (CHAR16 *)L"VT-100 Serial Console",\r
777 FALSE\r
778 );\r
779\r
780 break;\r
781\r
782 case VT100PLUSTYPE:\r
783 AddUnicodeString2 (\r
784 "eng",\r
785 gTerminalComponentName.SupportedLanguages,\r
786 &TerminalDevice->ControllerNameTable,\r
787 (CHAR16 *)L"VT-100+ Serial Console",\r
788 TRUE\r
789 );\r
790 AddUnicodeString2 (\r
791 "en",\r
792 gTerminalComponentName2.SupportedLanguages,\r
793 &TerminalDevice->ControllerNameTable,\r
794 (CHAR16 *)L"VT-100+ Serial Console",\r
795 FALSE\r
796 );\r
797\r
798 break;\r
799\r
800 case VTUTF8TYPE:\r
801 AddUnicodeString2 (\r
802 "eng",\r
803 gTerminalComponentName.SupportedLanguages,\r
804 &TerminalDevice->ControllerNameTable,\r
805 (CHAR16 *)L"VT-UTF8 Serial Console",\r
806 TRUE\r
807 );\r
808 AddUnicodeString2 (\r
809 "en",\r
810 gTerminalComponentName2.SupportedLanguages,\r
811 &TerminalDevice->ControllerNameTable,\r
812 (CHAR16 *)L"VT-UTF8 Serial Console",\r
813 FALSE\r
814 );\r
815\r
816 break;\r
817 }\r
95276127 818\r
95276127 819 //\r
e3dcffcc 820 // Build the device path for the child device\r
95276127 821 //\r
e3dcffcc 822 Status = SetTerminalDevicePath (\r
823 TerminalDevice->TerminalType,\r
824 ParentDevicePath,\r
825 &TerminalDevice->DevicePath\r
826 );\r
827 if (EFI_ERROR (Status)) {\r
828 goto Error;\r
829 }\r
95276127 830\r
abef1c7a 831 Status = TerminalConOutReset (SimpleTextOutput, FALSE);\r
832 if (EFI_ERROR (Status)) {\r
833 goto ReportError;\r
834 }\r
835\r
836 Status = TerminalConOutSetMode (SimpleTextOutput, 0);\r
837 if (EFI_ERROR (Status)) {\r
838 goto ReportError;\r
839 }\r
840\r
841 Status = TerminalConOutEnableCursor (SimpleTextOutput, TRUE);\r
842 if (EFI_ERROR (Status)) {\r
843 goto ReportError;\r
844 }\r
845\r
f0368006
RN
846 Status = gBS->CreateEvent (\r
847 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
848 TPL_NOTIFY,\r
849 TerminalConInTimerHandler,\r
850 TerminalDevice,\r
851 &TerminalDevice->TimerEvent\r
852 );\r
853 ASSERT_EFI_ERROR (Status);\r
854\r
855 Status = gBS->SetTimer (\r
856 TerminalDevice->TimerEvent,\r
857 TimerPeriodic,\r
858 KEYBOARD_TIMER_INTERVAL\r
859 );\r
860 ASSERT_EFI_ERROR (Status);\r
861\r
abef1c7a 862 Status = gBS->CreateEvent (\r
863 EVT_TIMER,\r
864 TPL_CALLBACK,\r
865 NULL,\r
866 NULL,\r
867 &TerminalDevice->TwoSecondTimeOut\r
868 );\r
f0368006 869 ASSERT_EFI_ERROR (Status);\r
abef1c7a 870\r
e3dcffcc 871 Status = gBS->InstallProtocolInterface (\r
872 &TerminalDevice->Handle,\r
873 &gEfiDevicePathProtocolGuid,\r
874 EFI_NATIVE_INTERFACE,\r
875 TerminalDevice->DevicePath\r
876 );\r
877 if (EFI_ERROR (Status)) {\r
878 goto Error;\r
879 }\r
95276127 880\r
95276127 881 //\r
e3dcffcc 882 // Register the Parent-Child relationship via\r
883 // EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
95276127 884 //\r
e3dcffcc 885 Status = gBS->OpenProtocol (\r
886 Controller,\r
887 &gEfiSerialIoProtocolGuid,\r
888 (VOID **) &TerminalDevice->SerialIo,\r
889 This->DriverBindingHandle,\r
890 TerminalDevice->Handle,\r
891 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
892 );\r
893 if (EFI_ERROR (Status)) {\r
894 goto Error;\r
895 }\r
95276127 896 }\r
95276127 897\r
3012ce5c 898 //\r
e3dcffcc 899 // Find the child handle, and get its TerminalDevice private data\r
3012ce5c 900 //\r
e3dcffcc 901 Status = gBS->OpenProtocolInformation (\r
902 Controller,\r
903 &gEfiSerialIoProtocolGuid,\r
904 &OpenInfoBuffer,\r
905 &EntryCount\r
906 );\r
907 if (!EFI_ERROR (Status)) {\r
908 Status = EFI_NOT_FOUND;\r
909 ASSERT (OpenInfoBuffer != NULL);\r
910 for (Index = 0; Index < EntryCount; Index++) {\r
911 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {\r
912 //\r
913 // Find the child terminal handle.\r
914 // Test whether the SimpleTxtIn and SimpleTxtOut have been published\r
915 //\r
916 Status = gBS->OpenProtocol (\r
917 OpenInfoBuffer[Index].ControllerHandle,\r
918 &gEfiSimpleTextInProtocolGuid,\r
919 (VOID **) &SimpleTextInput,\r
920 This->DriverBindingHandle,\r
921 OpenInfoBuffer[Index].ControllerHandle,\r
922 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
923 );\r
924 if (!EFI_ERROR (Status)) {\r
925 SimTxtInInstalled = TRUE;\r
926 TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (SimpleTextInput);\r
927 }\r
3012ce5c 928\r
e3dcffcc 929 Status = gBS->OpenProtocol (\r
930 OpenInfoBuffer[Index].ControllerHandle,\r
931 &gEfiSimpleTextOutProtocolGuid,\r
932 (VOID **) &SimpleTextOutput,\r
933 This->DriverBindingHandle,\r
934 OpenInfoBuffer[Index].ControllerHandle,\r
935 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
936 );\r
937 if (!EFI_ERROR (Status)) {\r
938 SimTxtOutInstalled = TRUE;\r
939 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);\r
940 }\r
941 Status = EFI_SUCCESS;\r
942 break;\r
943 }\r
944 }\r
95276127 945\r
e3dcffcc 946 FreePool (OpenInfoBuffer);\r
947 if (EFI_ERROR (Status)) {\r
948 goto ReportError;\r
949 }\r
950 } else {\r
95276127 951 goto ReportError;\r
952 }\r
953\r
e3dcffcc 954 ASSERT (TerminalDevice != NULL);\r
955 //\r
956 // Only do the reset if the device path is in the Conout variable\r
957 //\r
958 if (ConInSelected && !SimTxtInInstalled) {\r
959 Status = TerminalDevice->SimpleInput.Reset (\r
960 &TerminalDevice->SimpleInput,\r
961 FALSE\r
962 );\r
963 if (EFI_ERROR (Status)) {\r
964 //\r
965 // Need to report Error Code first\r
966 //\r
967 goto ReportError;\r
968 }\r
95276127 969 }\r
95276127 970\r
95276127 971 //\r
e3dcffcc 972 // Only output the configure string to remote terminal if the device path\r
973 // is in the Conout variable\r
95276127 974 //\r
e3dcffcc 975 if (ConOutSelected && !SimTxtOutInstalled) {\r
976 Status = TerminalDevice->SimpleTextOutput.SetAttribute (\r
977 &TerminalDevice->SimpleTextOutput,\r
978 EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)\r
979 );\r
980 if (EFI_ERROR (Status)) {\r
981 goto ReportError;\r
982 }\r
5bca971e 983\r
e3dcffcc 984 Status = TerminalDevice->SimpleTextOutput.Reset (\r
985 &TerminalDevice->SimpleTextOutput,\r
986 FALSE\r
987 );\r
988 if (EFI_ERROR (Status)) {\r
989 goto ReportError;\r
990 }\r
95276127 991\r
e3dcffcc 992 Status = TerminalDevice->SimpleTextOutput.SetMode (\r
993 &TerminalDevice->SimpleTextOutput,\r
994 0\r
995 );\r
996 if (EFI_ERROR (Status)) {\r
997 goto ReportError;\r
998 }\r
5bca971e 999\r
e3dcffcc 1000 Status = TerminalDevice->SimpleTextOutput.EnableCursor (\r
1001 &TerminalDevice->SimpleTextOutput,\r
1002 TRUE\r
1003 );\r
1004 if (EFI_ERROR (Status)) {\r
1005 goto ReportError;\r
1006 }\r
95276127 1007 }\r
f1aec6cc 1008\r
95276127 1009 //\r
e3dcffcc 1010 // Simple In/Out Protocol will not be installed onto the handle if the\r
1011 // device path to the handle is not present in the ConIn/ConOut\r
1012 // environment variable. But If RemainingDevicePath is NULL, then always\r
1013 // produce both Simple In and Simple Text Output Protocols. This is required\r
1014 // for the connect all sequences to make sure all possible consoles are\r
1015 // produced no matter what the current values of ConIn, ConOut, or StdErr are.\r
95276127 1016 //\r
e3dcffcc 1017 if (!SimTxtInInstalled && (ConInSelected || NullRemaining)) {\r
1018 Status = gBS->InstallMultipleProtocolInterfaces (\r
1019 &TerminalDevice->Handle,\r
1020 &gEfiSimpleTextInProtocolGuid,\r
1021 &TerminalDevice->SimpleInput,\r
1022 &gEfiSimpleTextInputExProtocolGuid,\r
1023 &TerminalDevice->SimpleInputEx,\r
1024 NULL\r
1025 );\r
1026 if (EFI_ERROR (Status)) {\r
1027 goto Error;\r
1028 }\r
95276127 1029 }\r
1030\r
e3dcffcc 1031 if (!SimTxtOutInstalled && (ConOutSelected || NullRemaining)) {\r
1032 Status = gBS->InstallProtocolInterface (\r
1033 &TerminalDevice->Handle,\r
1034 &gEfiSimpleTextOutProtocolGuid,\r
1035 EFI_NATIVE_INTERFACE,\r
1036 &TerminalDevice->SimpleTextOutput\r
1037 );\r
1038 if (EFI_ERROR (Status)) {\r
1039 goto Error;\r
1040 }\r
1041 }\r
95276127 1042 if (DefaultNode != NULL) {\r
1043 FreePool (DefaultNode);\r
1044 }\r
1045\r
1046 return EFI_SUCCESS;\r
1047\r
1048ReportError:\r
1049 //\r
1050 // Report error code before exiting\r
1051 //\r
e3dcffcc 1052 DevicePath = ParentDevicePath;\r
95276127 1053 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1054 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
f9876ecf 1055 (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),\r
95276127 1056 DevicePath\r
1057 );\r
1058\r
1059Error:\r
1060 //\r
1061 // Use the Stop() function to free all resources allocated in Start()\r
1062 //\r
1063 if (TerminalDevice != NULL) {\r
1064\r
1065 if (TerminalDevice->Handle != NULL) {\r
1066 This->Stop (This, Controller, 1, &TerminalDevice->Handle);\r
1067 } else {\r
1068\r
1069 if (TerminalDevice->TwoSecondTimeOut != NULL) {\r
1070 gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);\r
1071 }\r
1072\r
f0368006
RN
1073 if (TerminalDevice->TimerEvent != NULL) {\r
1074 gBS->CloseEvent (TerminalDevice->TimerEvent);\r
1075 }\r
1076\r
95276127 1077 if (TerminalDevice->SimpleInput.WaitForKey != NULL) {\r
1078 gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);\r
1079 }\r
1080\r
66aa04e4 1081 if (TerminalDevice->SimpleInputEx.WaitForKeyEx != NULL) {\r
1082 gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);\r
1083 }\r
1084\r
1085 TerminalFreeNotifyList (&TerminalDevice->NotifyList);\r
1086\r
5c998646 1087 if (TerminalDevice->RawFiFo != NULL) {\r
1088 FreePool (TerminalDevice->RawFiFo);\r
1089 }\r
1090 if (TerminalDevice->UnicodeFiFo != NULL) {\r
1091 FreePool (TerminalDevice->UnicodeFiFo);\r
1092 }\r
1093 if (TerminalDevice->EfiKeyFiFo != NULL) {\r
1094 FreePool (TerminalDevice->EfiKeyFiFo);\r
1095 }\r
1096\r
95276127 1097 if (TerminalDevice->ControllerNameTable != NULL) {\r
1098 FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);\r
1099 }\r
1100\r
1101 if (TerminalDevice->DevicePath != NULL) {\r
1102 FreePool (TerminalDevice->DevicePath);\r
1103 }\r
1104\r
1105 FreePool (TerminalDevice);\r
1106 }\r
1107 }\r
1108\r
1109 if (DefaultNode != NULL) {\r
1110 FreePool (DefaultNode);\r
1111 }\r
1112\r
1113 This->Stop (This, Controller, 0, NULL);\r
1114\r
1115 return Status;\r
1116}\r
1117\r
e49ef433 1118/**\r
ab76200c 1119 Stop this driver on Controller by closing Simple Text In, Simple Text\r
8fd98315 1120 In Ex, Simple Text Out protocol, and removing parent device path from\r
677fdb90 1121 Console Device Environment Variables.\r
e49ef433 1122\r
8fd98315 1123 @param This Protocol instance pointer.\r
ab76200c 1124 @param Controller Handle of device to stop driver on\r
8fd98315 1125 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of\r
1126 children is zero stop the entire bus driver.\r
1127 @param ChildHandleBuffer List of Child Handles to Stop.\r
e49ef433 1128\r
ab76200c 1129 @retval EFI_SUCCESS This driver is removed Controller.\r
8fd98315 1130 @retval other This driver could not be removed from this device.\r
e49ef433 1131\r
1132**/\r
95276127 1133EFI_STATUS\r
1134EFIAPI\r
1135TerminalDriverBindingStop (\r
1136 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1137 IN EFI_HANDLE Controller,\r
1138 IN UINTN NumberOfChildren,\r
1139 IN EFI_HANDLE *ChildHandleBuffer\r
1140 )\r
95276127 1141{\r
1142 EFI_STATUS Status;\r
1143 UINTN Index;\r
1144 BOOLEAN AllChildrenStopped;\r
1145 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;\r
1146 TERMINAL_DEV *TerminalDevice;\r
1147 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
1148 EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
1149 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1150\r
1151 Status = gBS->HandleProtocol (\r
1152 Controller,\r
1153 &gEfiDevicePathProtocolGuid,\r
1154 (VOID **) &DevicePath\r
1155 );\r
1156 if (EFI_ERROR (Status)) {\r
1157 return Status;\r
1158 }\r
95276127 1159\r
1160 //\r
1161 // Complete all outstanding transactions to Controller.\r
1162 // Don't allow any new transaction to Controller to be started.\r
1163 //\r
1164 if (NumberOfChildren == 0) {\r
1165 //\r
1166 // Close the bus driver\r
1167 //\r
1168 Status = gBS->OpenProtocol (\r
1169 Controller,\r
1170 &gEfiCallerIdGuid,\r
1171 (VOID **) &ParentDevicePath,\r
1172 This->DriverBindingHandle,\r
1173 Controller,\r
1174 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1175 );\r
1176 if (!EFI_ERROR (Status)) {\r
1177 //\r
1178 // Remove Parent Device Path from\r
1179 // the Console Device Environment Variables\r
1180 //\r
ff37790d
A
1181 TerminalRemoveConsoleDevVariable (L"ConInDev", ParentDevicePath);\r
1182 TerminalRemoveConsoleDevVariable (L"ConOutDev", ParentDevicePath);\r
1183 TerminalRemoveConsoleDevVariable (L"ErrOutDev", ParentDevicePath);\r
95276127 1184\r
1185 //\r
1186 // Uninstall the Terminal Driver's GUID Tag from the Serial controller\r
1187 //\r
1188 Status = gBS->UninstallMultipleProtocolInterfaces (\r
1189 Controller,\r
1190 &gEfiCallerIdGuid,\r
1191 ParentDevicePath,\r
1192 NULL\r
1193 );\r
1194\r
1195 //\r
1196 // Free the ParentDevicePath that was duplicated in Start()\r
1197 //\r
1198 if (!EFI_ERROR (Status)) {\r
1199 FreePool (ParentDevicePath);\r
1200 }\r
1201 }\r
1202\r
1203 gBS->CloseProtocol (\r
1204 Controller,\r
1205 &gEfiSerialIoProtocolGuid,\r
1206 This->DriverBindingHandle,\r
1207 Controller\r
1208 );\r
1209\r
1210 gBS->CloseProtocol (\r
1211 Controller,\r
1212 &gEfiDevicePathProtocolGuid,\r
1213 This->DriverBindingHandle,\r
1214 Controller\r
1215 );\r
1216\r
1217 return EFI_SUCCESS;\r
1218 }\r
1219\r
1220 AllChildrenStopped = TRUE;\r
1221\r
1222 for (Index = 0; Index < NumberOfChildren; Index++) {\r
1223\r
1224 Status = gBS->OpenProtocol (\r
1225 ChildHandleBuffer[Index],\r
1226 &gEfiSimpleTextOutProtocolGuid,\r
1227 (VOID **) &SimpleTextOutput,\r
1228 This->DriverBindingHandle,\r
1229 ChildHandleBuffer[Index],\r
1230 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1231 );\r
1232 if (!EFI_ERROR (Status)) {\r
1233\r
1234 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);\r
1235\r
1236 gBS->CloseProtocol (\r
1237 Controller,\r
1238 &gEfiSerialIoProtocolGuid,\r
1239 This->DriverBindingHandle,\r
1240 ChildHandleBuffer[Index]\r
1241 );\r
1242\r
1243 Status = gBS->UninstallMultipleProtocolInterfaces (\r
1244 ChildHandleBuffer[Index],\r
1245 &gEfiSimpleTextInProtocolGuid,\r
1246 &TerminalDevice->SimpleInput,\r
66aa04e4 1247 &gEfiSimpleTextInputExProtocolGuid,\r
1248 &TerminalDevice->SimpleInputEx,\r
95276127 1249 &gEfiSimpleTextOutProtocolGuid,\r
1250 &TerminalDevice->SimpleTextOutput,\r
1251 &gEfiDevicePathProtocolGuid,\r
1252 TerminalDevice->DevicePath,\r
1253 NULL\r
1254 );\r
1255 if (EFI_ERROR (Status)) {\r
1256 gBS->OpenProtocol (\r
1257 Controller,\r
1258 &gEfiSerialIoProtocolGuid,\r
1259 (VOID **) &SerialIo,\r
1260 This->DriverBindingHandle,\r
1261 ChildHandleBuffer[Index],\r
1262 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
1263 );\r
1264 } else {\r
1265\r
1266 if (TerminalDevice->ControllerNameTable != NULL) {\r
1267 FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);\r
1268 }\r
1269\r
f0368006 1270 gBS->CloseEvent (TerminalDevice->TimerEvent);\r
95276127 1271 gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);\r
1272 gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);\r
66aa04e4 1273 gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);\r
1274 TerminalFreeNotifyList (&TerminalDevice->NotifyList);\r
95276127 1275 FreePool (TerminalDevice->DevicePath);\r
1276 FreePool (TerminalDevice);\r
1277 }\r
1278 }\r
1279\r
1280 if (EFI_ERROR (Status)) {\r
1281 AllChildrenStopped = FALSE;\r
1282 }\r
1283 }\r
1284\r
1285 if (!AllChildrenStopped) {\r
1286 return EFI_DEVICE_ERROR;\r
1287 }\r
1288\r
1289 return EFI_SUCCESS;\r
1290}\r
1291\r
8fd98315 1292/**\r
1293 Update terminal device path in Console Device Environment Variables.\r
1294\r
1295 @param VariableName The Console Device Environment Variable.\r
11baadb6 1296 @param ParentDevicePath The terminal device path to be updated.\r
8fd98315 1297\r
8fd98315 1298**/\r
95276127 1299VOID\r
1300TerminalUpdateConsoleDevVariable (\r
1301 IN CHAR16 *VariableName,\r
1302 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath\r
1303 )\r
1304{\r
1305 EFI_STATUS Status;\r
1306 UINTN VariableSize;\r
1307 UINT8 TerminalType;\r
1308 EFI_DEVICE_PATH_PROTOCOL *Variable;\r
1309 EFI_DEVICE_PATH_PROTOCOL *NewVariable;\r
1310 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
1311\r
95276127 1312 //\r
1313 // Get global variable and its size according to the name given.\r
1314 //\r
e3dcffcc 1315 Variable = GetEfiGlobalVariable (VariableName);\r
1316 if (Variable == NULL) {\r
1317 return;\r
1318 }\r
1319\r
95276127 1320 //\r
1321 // Append terminal device path onto the variable.\r
1322 //\r
e49ef433 1323 for (TerminalType = PCANSITYPE; TerminalType <= VTUTF8TYPE; TerminalType++) {\r
95276127 1324 SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);\r
1325 NewVariable = AppendDevicePathInstance (Variable, TempDevicePath);\r
1326 if (Variable != NULL) {\r
1327 FreePool (Variable);\r
1328 }\r
1329\r
1330 if (TempDevicePath != NULL) {\r
1331 FreePool (TempDevicePath);\r
1332 }\r
1333\r
1334 Variable = NewVariable;\r
1335 }\r
1336\r
1337 VariableSize = GetDevicePathSize (Variable);\r
1338\r
1339 Status = gRT->SetVariable (\r
1340 VariableName,\r
1341 &gEfiGlobalVariableGuid,\r
1342 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
1343 VariableSize,\r
1344 Variable\r
1345 );\r
1346 ASSERT_EFI_ERROR (Status);\r
1347 FreePool (Variable);\r
1348\r
1349 return ;\r
1350}\r
1351\r
e49ef433 1352\r
1353/**\r
8fd98315 1354 Remove terminal device path from Console Device Environment Variables.\r
e49ef433 1355\r
8fd98315 1356 @param VariableName Console Device Environment Variables.\r
11baadb6 1357 @param ParentDevicePath The terminal device path to be updated.\r
e49ef433 1358\r
e49ef433 1359**/\r
95276127 1360VOID\r
1361TerminalRemoveConsoleDevVariable (\r
1362 IN CHAR16 *VariableName,\r
1363 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath\r
1364 )\r
95276127 1365{\r
1366 EFI_STATUS Status;\r
1367 BOOLEAN FoundOne;\r
1368 BOOLEAN Match;\r
1369 UINTN VariableSize;\r
1370 UINTN InstanceSize;\r
1371 UINT8 TerminalType;\r
1372 EFI_DEVICE_PATH_PROTOCOL *Instance;\r
1373 EFI_DEVICE_PATH_PROTOCOL *Variable;\r
1374 EFI_DEVICE_PATH_PROTOCOL *OriginalVariable;\r
1375 EFI_DEVICE_PATH_PROTOCOL *NewVariable;\r
1376 EFI_DEVICE_PATH_PROTOCOL *SavedNewVariable;\r
1377 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
1378\r
95276127 1379 Instance = NULL;\r
1380\r
1381 //\r
1382 // Get global variable and its size according to the name given.\r
1383 //\r
e3dcffcc 1384 Variable = GetEfiGlobalVariable (VariableName);\r
95276127 1385 if (Variable == NULL) {\r
1386 return ;\r
1387 }\r
1388\r
1389 FoundOne = FALSE;\r
1390 OriginalVariable = Variable;\r
1391 NewVariable = NULL;\r
1392\r
1393 //\r
1394 // Get first device path instance from Variable\r
1395 //\r
1396 Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);\r
1397 if (Instance == NULL) {\r
1398 FreePool (OriginalVariable);\r
1399 return ;\r
1400 }\r
1401 //\r
1402 // Loop through all the device path instances of Variable\r
1403 //\r
1404 do {\r
1405 //\r
1406 // Loop through all the terminal types that this driver supports\r
1407 //\r
1408 Match = FALSE;\r
e49ef433 1409 for (TerminalType = PCANSITYPE; TerminalType <= VTUTF8TYPE; TerminalType++) {\r
95276127 1410\r
1411 SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);\r
1412\r
1413 //\r
11baadb6 1414 // Compare the generated device path to the current device path instance\r
95276127 1415 //\r
1416 if (TempDevicePath != NULL) {\r
1417 if (CompareMem (Instance, TempDevicePath, InstanceSize) == 0) {\r
1418 Match = TRUE;\r
1419 FoundOne = TRUE;\r
1420 }\r
1421\r
1422 FreePool (TempDevicePath);\r
1423 }\r
1424 }\r
1425 //\r
1426 // If a match was not found, then keep the current device path instance\r
1427 //\r
1428 if (!Match) {\r
1429 SavedNewVariable = NewVariable;\r
1430 NewVariable = AppendDevicePathInstance (NewVariable, Instance);\r
1431 if (SavedNewVariable != NULL) {\r
1432 FreePool (SavedNewVariable);\r
1433 }\r
1434 }\r
1435 //\r
1436 // Get next device path instance from Variable\r
1437 //\r
1438 FreePool (Instance);\r
1439 Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);\r
1440 } while (Instance != NULL);\r
1441\r
1442 FreePool (OriginalVariable);\r
1443\r
1444 if (FoundOne) {\r
1445 VariableSize = GetDevicePathSize (NewVariable);\r
1446\r
1447 Status = gRT->SetVariable (\r
1448 VariableName,\r
1449 &gEfiGlobalVariableGuid,\r
1450 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
1451 VariableSize,\r
1452 NewVariable\r
1453 );\r
1454 ASSERT_EFI_ERROR (Status);\r
1455 }\r
1456\r
1457 if (NewVariable != NULL) {\r
1458 FreePool (NewVariable);\r
1459 }\r
1460\r
1461 return ;\r
1462}\r
1463\r
8fd98315 1464/**\r
11baadb6 1465 Build terminal device path according to terminal type.\r
8fd98315 1466\r
1467 @param TerminalType The terminal type is PC ANSI, VT100, VT100+ or VT-UTF8.\r
11baadb6 1468 @param ParentDevicePath Parent device path.\r
8fd98315 1469 @param TerminalDevicePath Returned terminal device path, if building successfully.\r
1470\r
1471 @retval EFI_UNSUPPORTED Terminal does not belong to the supported type.\r
1472 @retval EFI_OUT_OF_RESOURCES Generate terminal device path failed.\r
1473 @retval EFI_SUCCESS Build terminal device path successfully.\r
1474\r
1475**/\r
95276127 1476EFI_STATUS\r
1477SetTerminalDevicePath (\r
1478 IN UINT8 TerminalType,\r
1479 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
1480 OUT EFI_DEVICE_PATH_PROTOCOL **TerminalDevicePath\r
1481 )\r
1482{\r
1483 VENDOR_DEVICE_PATH Node;\r
1484\r
1485 *TerminalDevicePath = NULL;\r
1486 Node.Header.Type = MESSAGING_DEVICE_PATH;\r
1487 Node.Header.SubType = MSG_VENDOR_DP;\r
1488\r
1489 //\r
ab76200c 1490 // Generate terminal device path node according to terminal type.\r
95276127 1491 //\r
1492 switch (TerminalType) {\r
1493\r
e49ef433 1494 case PCANSITYPE:\r
ab76200c 1495 CopyGuid (&Node.Guid, &gEfiPcAnsiGuid);\r
95276127 1496 break;\r
1497\r
e49ef433 1498 case VT100TYPE:\r
ab76200c 1499 CopyGuid (&Node.Guid, &gEfiVT100Guid);\r
95276127 1500 break;\r
1501\r
e49ef433 1502 case VT100PLUSTYPE:\r
ab76200c 1503 CopyGuid (&Node.Guid, &gEfiVT100PlusGuid);\r
95276127 1504 break;\r
1505\r
e49ef433 1506 case VTUTF8TYPE:\r
ab76200c 1507 CopyGuid (&Node.Guid, &gEfiVTUTF8Guid);\r
95276127 1508 break;\r
1509\r
1510 default:\r
1511 return EFI_UNSUPPORTED;\r
95276127 1512 }\r
1513\r
ab76200c 1514 //\r
1515 // Get VENDOR_DEVCIE_PATH size and put into Node.Header\r
1516 //\r
95276127 1517 SetDevicePathNodeLength (\r
1518 &Node.Header,\r
1519 sizeof (VENDOR_DEVICE_PATH)\r
1520 );\r
ab76200c 1521\r
95276127 1522 //\r
ab76200c 1523 // Append the terminal node onto parent device path\r
95276127 1524 // to generate a complete terminal device path.\r
1525 //\r
1526 *TerminalDevicePath = AppendDevicePathNode (\r
1527 ParentDevicePath,\r
1528 (EFI_DEVICE_PATH_PROTOCOL *) &Node\r
1529 );\r
1530 if (*TerminalDevicePath == NULL) {\r
1531 return EFI_OUT_OF_RESOURCES;\r
1532 }\r
1533\r
1534 return EFI_SUCCESS;\r
1535}\r
1536\r
97a079ed
A
1537/**\r
1538 The user Entry Point for module Terminal. The user code starts with this function.\r
1539\r
ab76200c 1540 @param ImageHandle The firmware allocated handle for the EFI image.\r
1541 @param SystemTable A pointer to the EFI System Table.\r
fb0b259e 1542\r
97a079ed
A
1543 @retval EFI_SUCCESS The entry point is executed successfully.\r
1544 @retval other Some error occurs when executing this entry point.\r
1545\r
1546**/\r
1547EFI_STATUS\r
1548EFIAPI\r
1549InitializeTerminal(\r
1550 IN EFI_HANDLE ImageHandle,\r
1551 IN EFI_SYSTEM_TABLE *SystemTable\r
1552 )\r
1553{\r
1554 EFI_STATUS Status;\r
1555\r
1556 //\r
1557 // Install driver model protocol(s).\r
1558 //\r
5bca971e 1559 Status = EfiLibInstallDriverBindingComponentName2 (\r
97a079ed
A
1560 ImageHandle,\r
1561 SystemTable,\r
1562 &gTerminalDriverBinding,\r
1563 ImageHandle,\r
1564 &gTerminalComponentName,\r
5bca971e 1565 &gTerminalComponentName2\r
97a079ed
A
1566 );\r
1567 ASSERT_EFI_ERROR (Status);\r
1568\r
97a079ed
A
1569 return Status;\r
1570}\r
f1aec6cc 1571\r
1572/**\r
1573 Check if the device supports hot-plug through its device path.\r
1574\r
1575 This function could be updated to check more types of Hot Plug devices.\r
1576 Currently, it checks USB and PCCard device.\r
1577\r
1578 @param DevicePath Pointer to device's device path.\r
1579\r
1580 @retval TRUE The devcie is a hot-plug device\r
1581 @retval FALSE The devcie is not a hot-plug device.\r
1582\r
1583**/\r
1584BOOLEAN\r
1585IsHotPlugDevice (\r
1586 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
1587 )\r
1588{\r
1589 EFI_DEVICE_PATH_PROTOCOL *CheckDevicePath;\r
1590\r
1591 CheckDevicePath = DevicePath;\r
1592 while (!IsDevicePathEnd (CheckDevicePath)) {\r
1593 //\r
1594 // Check device whether is hot plug device or not throught Device Path\r
e3dcffcc 1595 //\r
f1aec6cc 1596 if ((DevicePathType (CheckDevicePath) == MESSAGING_DEVICE_PATH) &&\r
1597 (DevicePathSubType (CheckDevicePath) == MSG_USB_DP ||\r
1598 DevicePathSubType (CheckDevicePath) == MSG_USB_CLASS_DP ||\r
1599 DevicePathSubType (CheckDevicePath) == MSG_USB_WWID_DP)) {\r
1600 //\r
1601 // If Device is USB device\r
1602 //\r
1603 return TRUE;\r
1604 }\r
1605 if ((DevicePathType (CheckDevicePath) == HARDWARE_DEVICE_PATH) &&\r
1606 (DevicePathSubType (CheckDevicePath) == HW_PCCARD_DP)) {\r
1607 //\r
1608 // If Device is PCCard\r
1609 //\r
1610 return TRUE;\r
1611 }\r
e3dcffcc 1612\r
f1aec6cc 1613 CheckDevicePath = NextDevicePathNode (CheckDevicePath);\r
1614 }\r
1615\r
1616 return FALSE;\r
1617}\r
1618\r