]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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
8a53ea9d 5Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
9d510e61 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
95276127 7\r
fb0b259e 8**/\r
95276127 9\r
95276127 10#include "Terminal.h"\r
11\r
95276127 12//\r
13// Globals\r
14//\r
1436aea4 15EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding = {\r
95276127 16 TerminalDriverBindingSupported,\r
17 TerminalDriverBindingStart,\r
18 TerminalDriverBindingStop,\r
19 0xa,\r
20 NULL,\r
21 NULL\r
22};\r
23\r
f9163275 24EFI_GUID *mTerminalType[] = {\r
6b88ceec
A
25 &gEfiPcAnsiGuid,\r
26 &gEfiVT100Guid,\r
27 &gEfiVT100PlusGuid,\r
6e3227c8 28 &gEfiVTUTF8Guid,\r
8a53ea9d
ZG
29 &gEfiTtyTermGuid,\r
30 &gEdkiiLinuxTermGuid,\r
31 &gEdkiiXtermR6Guid,\r
32 &gEdkiiVT400Guid,\r
33 &gEdkiiSCOTermGuid\r
6b88ceec
A
34};\r
35\r
1436aea4 36CHAR16 *mSerialConsoleNames[] = {\r
fa3f99e5
RN
37 L"PC-ANSI Serial Console",\r
38 L"VT-100 Serial Console",\r
39 L"VT-100+ Serial Console",\r
40 L"VT-UTF8 Serial Console",\r
8a53ea9d
ZG
41 L"Tty Terminal Serial Console",\r
42 L"Linux Terminal Serial Console",\r
43 L"Xterm R6 Serial Console",\r
44 L"VT-400 Serial Console",\r
45 L"SCO Terminal Serial Console"\r
fa3f99e5
RN
46};\r
47\r
204ba917 48TERMINAL_DEV mTerminalDevTemplate = {\r
6b88ceec
A
49 TERMINAL_DEV_SIGNATURE,\r
50 NULL,\r
51 0,\r
52 NULL,\r
53 NULL,\r
54 { // SimpleTextInput\r
55 TerminalConInReset,\r
56 TerminalConInReadKeyStroke,\r
57 NULL\r
58 },\r
59 { // SimpleTextOutput\r
60 TerminalConOutReset,\r
61 TerminalConOutOutputString,\r
62 TerminalConOutTestString,\r
63 TerminalConOutQueryMode,\r
64 TerminalConOutSetMode,\r
65 TerminalConOutSetAttribute,\r
66 TerminalConOutClearScreen,\r
67 TerminalConOutSetCursorPosition,\r
68 TerminalConOutEnableCursor,\r
69 NULL\r
70 },\r
1436aea4
MK
71 { // SimpleTextOutputMode\r
72 1, // MaxMode\r
73 0, // Mode\r
74 EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK), // Attribute\r
75 0, // CursorColumn\r
76 0, // CursorRow\r
77 TRUE // CursorVisible\r
6b88ceec 78 },\r
79d07c66 79 NULL, // TerminalConsoleModeData\r
1436aea4 80 0, // SerialInTimeOut\r
5c998646 81\r
82 NULL, // RawFifo\r
83 NULL, // UnicodeFiFo\r
84 NULL, // EfiKeyFiFo\r
47b612db 85 NULL, // EfiKeyFiFoForNotify\r
5c998646 86\r
6b88ceec 87 NULL, // ControllerNameTable\r
f0368006 88 NULL, // TimerEvent\r
11baadb6 89 NULL, // TwoSecondTimeOut\r
6b88ceec
A
90 INPUT_STATE_DEFAULT,\r
91 RESET_STATE_DEFAULT,\r
014f93ac 92 {\r
1436aea4
MK
93 0,\r
94 0,\r
95 0\r
014f93ac
RF
96 },\r
97 0,\r
66aa04e4 98 FALSE,\r
99 { // SimpleTextInputEx\r
100 TerminalConInResetEx,\r
101 TerminalConInReadKeyStrokeEx,\r
102 NULL,\r
103 TerminalConInSetState,\r
104 TerminalConInRegisterKeyNotify,\r
105 TerminalConInUnregisterKeyNotify,\r
106 },\r
11baadb6 107 { // NotifyList\r
66aa04e4 108 NULL,\r
109 NULL,\r
47b612db
SZ
110 },\r
111 NULL // KeyNotifyProcessEvent\r
6b88ceec
A
112};\r
113\r
1436aea4
MK
114TERMINAL_CONSOLE_MODE_DATA mTerminalConsoleModeData[] = {\r
115 { 80, 25 },\r
116 { 80, 50 },\r
117 { 100, 31 },\r
79d07c66 118 //\r
119 // New modes can be added here.\r
79d07c66 120 //\r
79d07c66 121};\r
122\r
f9163275
RN
123/**\r
124 Convert the GUID representation of terminal type to enum type.\r
125\r
126 @param Guid The GUID representation of terminal type.\r
127\r
128 @return The terminal type in enum type.\r
129**/\r
130TERMINAL_TYPE\r
131TerminalTypeFromGuid (\r
1436aea4
MK
132 IN EFI_GUID *Guid\r
133 )\r
f9163275 134{\r
1436aea4 135 TERMINAL_TYPE Type;\r
f9163275
RN
136\r
137 for (Type = 0; Type < ARRAY_SIZE (mTerminalType); Type++) {\r
138 if (CompareGuid (Guid, mTerminalType[Type])) {\r
139 break;\r
140 }\r
141 }\r
1436aea4 142\r
f9163275
RN
143 return Type;\r
144}\r
145\r
8fd98315 146/**\r
677fdb90 147 Test to see if this driver supports Controller.\r
8fd98315 148\r
149 @param This Protocol instance pointer.\r
ab76200c 150 @param Controller Handle of device to test\r
8fd98315 151 @param RemainingDevicePath Optional parameter use to pick a specific child\r
152 device to start.\r
153\r
ab76200c 154 @retval EFI_SUCCESS This driver supports this device.\r
155 @retval EFI_ALREADY_STARTED This driver is already running on this device.\r
156 @retval other This driver does not support this device.\r
6b88ceec 157\r
8fd98315 158**/\r
95276127 159EFI_STATUS\r
160EFIAPI\r
161TerminalDriverBindingSupported (\r
1436aea4
MK
162 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
163 IN EFI_HANDLE Controller,\r
164 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
95276127 165 )\r
166{\r
167 EFI_STATUS Status;\r
168 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
169 EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
170 VENDOR_DEVICE_PATH *Node;\r
171\r
172 //\r
173 // If remaining device path is not NULL, then make sure it is a\r
174 // device path that describes a terminal communications protocol.\r
175 //\r
176 if (RemainingDevicePath != NULL) {\r
95276127 177 //\r
e3dcffcc 178 // Check if RemainingDevicePath is the End of Device Path Node,\r
af4a6385 179 // if yes, go on checking other conditions\r
95276127 180 //\r
af4a6385 181 if (!IsDevicePathEnd (RemainingDevicePath)) {\r
182 //\r
183 // If RemainingDevicePath isn't the End of Device Path Node,\r
184 // check its validation\r
185 //\r
1436aea4 186 Node = (VENDOR_DEVICE_PATH *)RemainingDevicePath;\r
e3dcffcc 187\r
1436aea4
MK
188 if ((Node->Header.Type != MESSAGING_DEVICE_PATH) ||\r
189 (Node->Header.SubType != MSG_VENDOR_DP) ||\r
190 (DevicePathNodeLength (&Node->Header) != sizeof (VENDOR_DEVICE_PATH)))\r
191 {\r
af4a6385 192 return EFI_UNSUPPORTED;\r
af4a6385 193 }\r
1436aea4 194\r
af4a6385 195 //\r
8a53ea9d
ZG
196 // only supports PC ANSI, VT100, VT100+, VT-UTF8, TtyTerm\r
197 // Linux, XtermR6, VT400 and SCO terminal types\r
af4a6385 198 //\r
f9163275 199 if (TerminalTypeFromGuid (&Node->Guid) == ARRAY_SIZE (mTerminalType)) {\r
af4a6385 200 return EFI_UNSUPPORTED;\r
201 }\r
95276127 202 }\r
203 }\r
1436aea4 204\r
95276127 205 //\r
206 // Open the IO Abstraction(s) needed to perform the supported test\r
af4a6385 207 // The Controller must support the Serial I/O Protocol.\r
208 // This driver is a bus driver with at most 1 child device, so it is\r
209 // ok for it to be already started.\r
95276127 210 //\r
211 Status = gBS->OpenProtocol (\r
212 Controller,\r
af4a6385 213 &gEfiSerialIoProtocolGuid,\r
1436aea4 214 (VOID **)&SerialIo,\r
95276127 215 This->DriverBindingHandle,\r
216 Controller,\r
217 EFI_OPEN_PROTOCOL_BY_DRIVER\r
218 );\r
219 if (Status == EFI_ALREADY_STARTED) {\r
220 return EFI_SUCCESS;\r
221 }\r
222\r
223 if (EFI_ERROR (Status)) {\r
224 return Status;\r
225 }\r
226\r
af4a6385 227 //\r
228 // Close the I/O Abstraction(s) used to perform the supported test\r
229 //\r
95276127 230 gBS->CloseProtocol (\r
1436aea4
MK
231 Controller,\r
232 &gEfiSerialIoProtocolGuid,\r
233 This->DriverBindingHandle,\r
234 Controller\r
235 );\r
95276127 236\r
237 //\r
af4a6385 238 // Open the EFI Device Path protocol needed to perform the supported test\r
95276127 239 //\r
240 Status = gBS->OpenProtocol (\r
241 Controller,\r
af4a6385 242 &gEfiDevicePathProtocolGuid,\r
1436aea4 243 (VOID **)&ParentDevicePath,\r
95276127 244 This->DriverBindingHandle,\r
245 Controller,\r
246 EFI_OPEN_PROTOCOL_BY_DRIVER\r
247 );\r
248 if (Status == EFI_ALREADY_STARTED) {\r
249 return EFI_SUCCESS;\r
250 }\r
251\r
252 if (EFI_ERROR (Status)) {\r
253 return Status;\r
254 }\r
af4a6385 255\r
95276127 256 //\r
af4a6385 257 // Close protocol, don't use device path protocol in the Support() function\r
95276127 258 //\r
259 gBS->CloseProtocol (\r
1436aea4
MK
260 Controller,\r
261 &gEfiDevicePathProtocolGuid,\r
262 This->DriverBindingHandle,\r
263 Controller\r
264 );\r
95276127 265\r
266 return Status;\r
267}\r
268\r
e3dcffcc 269/**\r
270 Free notify functions list.\r
271\r
272 @param ListHead The list head\r
273\r
274 @retval EFI_SUCCESS Free the notify list successfully.\r
275 @retval EFI_INVALID_PARAMETER ListHead is NULL.\r
276\r
277**/\r
278EFI_STATUS\r
279TerminalFreeNotifyList (\r
1436aea4 280 IN OUT LIST_ENTRY *ListHead\r
e3dcffcc 281 )\r
282{\r
1436aea4 283 TERMINAL_CONSOLE_IN_EX_NOTIFY *NotifyNode;\r
e3dcffcc 284\r
285 if (ListHead == NULL) {\r
286 return EFI_INVALID_PARAMETER;\r
287 }\r
1436aea4 288\r
e3dcffcc 289 while (!IsListEmpty (ListHead)) {\r
290 NotifyNode = CR (\r
291 ListHead->ForwardLink,\r
292 TERMINAL_CONSOLE_IN_EX_NOTIFY,\r
293 NotifyEntry,\r
294 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
295 );\r
296 RemoveEntryList (ListHead->ForwardLink);\r
297 FreePool (NotifyNode);\r
298 }\r
299\r
300 return EFI_SUCCESS;\r
301}\r
302\r
79d07c66 303/**\r
304 Initialize all the text modes which the terminal console supports.\r
305\r
306 It returns information for available text modes that the terminal can support.\r
307\r
308 @param[out] TextModeCount The total number of text modes that terminal console supports.\r
79d07c66 309\r
390b95a4
RN
310 @return The buffer to the text modes column and row information.\r
311 Caller is responsible to free it when it's non-NULL.\r
79d07c66 312\r
313**/\r
390b95a4 314TERMINAL_CONSOLE_MODE_DATA *\r
79d07c66 315InitializeTerminalConsoleTextMode (\r
1436aea4
MK
316 OUT INT32 *TextModeCount\r
317 )\r
79d07c66 318{\r
390b95a4
RN
319 TERMINAL_CONSOLE_MODE_DATA *TextModeData;\r
320\r
321 ASSERT (TextModeCount != NULL);\r
322\r
390b95a4
RN
323 TextModeData = AllocateCopyPool (sizeof (mTerminalConsoleModeData), mTerminalConsoleModeData);\r
324 if (TextModeData == NULL) {\r
325 return NULL;\r
79d07c66 326 }\r
1436aea4 327\r
390b95a4
RN
328 *TextModeCount = ARRAY_SIZE (mTerminalConsoleModeData);\r
329\r
db52c7f7 330 DEBUG_CODE_BEGIN ();\r
1436aea4
MK
331 INT32 Index;\r
332\r
333 for (Index = 0; Index < *TextModeCount; Index++) {\r
334 DEBUG ((\r
335 DEBUG_INFO,\r
336 "Terminal - Mode %d, Column = %d, Row = %d\n",\r
337 Index,\r
338 TextModeData[Index].Columns,\r
339 TextModeData[Index].Rows\r
340 ));\r
341 }\r
342\r
db52c7f7 343 DEBUG_CODE_END ();\r
390b95a4 344 return TextModeData;\r
79d07c66 345}\r
e3dcffcc 346\r
b7cf1c07
RN
347/**\r
348 Stop the terminal state machine.\r
349\r
350 @param TerminalDevice The terminal device.\r
351**/\r
352VOID\r
353StopTerminalStateMachine (\r
1436aea4 354 TERMINAL_DEV *TerminalDevice\r
b7cf1c07
RN
355 )\r
356{\r
1436aea4 357 EFI_TPL OriginalTpl;\r
b7cf1c07
RN
358\r
359 OriginalTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
360\r
361 gBS->CloseEvent (TerminalDevice->TimerEvent);\r
362 gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);\r
363\r
364 gBS->RestoreTPL (OriginalTpl);\r
365}\r
366\r
367/**\r
368 Start the terminal state machine.\r
369\r
370 @param TerminalDevice The terminal device.\r
371**/\r
372VOID\r
373StartTerminalStateMachine (\r
1436aea4 374 TERMINAL_DEV *TerminalDevice\r
b7cf1c07
RN
375 )\r
376{\r
1436aea4
MK
377 EFI_STATUS Status;\r
378\r
b7cf1c07
RN
379 Status = gBS->CreateEvent (\r
380 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
381 TPL_NOTIFY,\r
382 TerminalConInTimerHandler,\r
383 TerminalDevice,\r
384 &TerminalDevice->TimerEvent\r
385 );\r
386 ASSERT_EFI_ERROR (Status);\r
387\r
388 Status = gBS->SetTimer (\r
389 TerminalDevice->TimerEvent,\r
390 TimerPeriodic,\r
391 KEYBOARD_TIMER_INTERVAL\r
392 );\r
393 ASSERT_EFI_ERROR (Status);\r
394\r
395 Status = gBS->CreateEvent (\r
396 EVT_TIMER,\r
397 TPL_CALLBACK,\r
398 NULL,\r
399 NULL,\r
400 &TerminalDevice->TwoSecondTimeOut\r
401 );\r
402 ASSERT_EFI_ERROR (Status);\r
403}\r
404\r
fa3f99e5
RN
405/**\r
406 Initialize the controller name table.\r
407\r
408 @param TerminalType The terminal type.\r
409 @param ControllerNameTable The controller name table.\r
410\r
411 @retval EFI_SUCCESS The controller name table is initialized successfully.\r
412 @retval others Return status of AddUnicodeString2 ().\r
413**/\r
414EFI_STATUS\r
415InitializeControllerNameTable (\r
416 TERMINAL_TYPE TerminalType,\r
417 EFI_UNICODE_STRING_TABLE **ControllerNameTable\r
1436aea4 418 )\r
fa3f99e5
RN
419{\r
420 EFI_STATUS Status;\r
421 EFI_UNICODE_STRING_TABLE *Table;\r
422\r
423 ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));\r
1436aea4 424 Table = NULL;\r
fa3f99e5
RN
425 Status = AddUnicodeString2 (\r
426 "eng",\r
427 gTerminalComponentName.SupportedLanguages,\r
428 &Table,\r
429 mSerialConsoleNames[TerminalType],\r
430 TRUE\r
431 );\r
432 if (!EFI_ERROR (Status)) {\r
433 Status = AddUnicodeString2 (\r
434 "en",\r
435 gTerminalComponentName2.SupportedLanguages,\r
436 &Table,\r
437 mSerialConsoleNames[TerminalType],\r
438 FALSE\r
439 );\r
440 if (EFI_ERROR (Status)) {\r
441 FreeUnicodeStringTable (Table);\r
442 }\r
443 }\r
1436aea4 444\r
fa3f99e5
RN
445 if (!EFI_ERROR (Status)) {\r
446 *ControllerNameTable = Table;\r
447 }\r
1436aea4 448\r
fa3f99e5
RN
449 return Status;\r
450}\r
451\r
e49ef433 452/**\r
ab76200c 453 Start this driver on Controller by opening a Serial IO protocol,\r
8fd98315 454 reading Device Path, and creating a child handle with a Simple Text In,\r
455 Simple Text In Ex and Simple Text Out protocol, and device path protocol.\r
456 And store Console Device Environment Variables.\r
e49ef433 457\r
8fd98315 458 @param This Protocol instance pointer.\r
ab76200c 459 @param Controller Handle of device to bind driver to\r
8fd98315 460 @param RemainingDevicePath Optional parameter use to pick a specific child\r
461 device to start.\r
e49ef433 462\r
ab76200c 463 @retval EFI_SUCCESS This driver is added to Controller.\r
464 @retval EFI_ALREADY_STARTED This driver is already running on Controller.\r
465 @retval other This driver does not support this device.\r
e49ef433 466\r
467**/\r
95276127 468EFI_STATUS\r
469EFIAPI\r
470TerminalDriverBindingStart (\r
1436aea4
MK
471 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
472 IN EFI_HANDLE Controller,\r
473 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
95276127 474 )\r
95276127 475{\r
1436aea4
MK
476 EFI_STATUS Status;\r
477 EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
478 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
479 EFI_DEVICE_PATH_PROTOCOL *Vendor;\r
480 EFI_HANDLE SerialIoHandle;\r
481 EFI_SERIAL_IO_MODE *Mode;\r
482 UINTN SerialInTimeOut;\r
483 TERMINAL_DEV *TerminalDevice;\r
484 UINT8 TerminalType;\r
485 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;\r
486 UINTN EntryCount;\r
487 UINTN Index;\r
488 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;\r
489 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextInput;\r
490 EFI_UNICODE_STRING_TABLE *ControllerNameTable;\r
f7c11d9b 491\r
95276127 492 //\r
493 // Get the Device Path Protocol to build the device path of the child device\r
494 //\r
495 Status = gBS->OpenProtocol (\r
496 Controller,\r
497 &gEfiDevicePathProtocolGuid,\r
1436aea4 498 (VOID **)&ParentDevicePath,\r
95276127 499 This->DriverBindingHandle,\r
500 Controller,\r
501 EFI_OPEN_PROTOCOL_BY_DRIVER\r
502 );\r
f7c11d9b 503 ASSERT ((Status == EFI_SUCCESS) || (Status == EFI_ALREADY_STARTED));\r
ebafede9
RN
504 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
505 return Status;\r
506 }\r
95276127 507\r
508 //\r
509 // Open the Serial I/O Protocol BY_DRIVER. It might already be started.\r
510 //\r
511 Status = gBS->OpenProtocol (\r
512 Controller,\r
513 &gEfiSerialIoProtocolGuid,\r
1436aea4 514 (VOID **)&SerialIo,\r
95276127 515 This->DriverBindingHandle,\r
516 Controller,\r
517 EFI_OPEN_PROTOCOL_BY_DRIVER\r
518 );\r
f7c11d9b 519 ASSERT ((Status == EFI_SUCCESS) || (Status == EFI_ALREADY_STARTED));\r
ebafede9
RN
520 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
521 return Status;\r
522 }\r
95276127 523\r
f7c11d9b 524 if (!IsHotPlugDevice (ParentDevicePath)) {\r
95276127 525 //\r
f7c11d9b
RN
526 // if the serial device is a hot plug device, do not update the\r
527 // ConInDev, ConOutDev, and StdErrDev variables.\r
95276127 528 //\r
f7c11d9b
RN
529 TerminalUpdateConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME, ParentDevicePath);\r
530 TerminalUpdateConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME, ParentDevicePath);\r
531 TerminalUpdateConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME, ParentDevicePath);\r
95276127 532 }\r
e3dcffcc 533\r
95276127 534 //\r
f7c11d9b 535 // Do not create any child for END remaining device path.\r
95276127 536 //\r
f7c11d9b
RN
537 if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) {\r
538 return EFI_SUCCESS;\r
539 }\r
95276127 540\r
f7c11d9b 541 if (Status == EFI_ALREADY_STARTED) {\r
f7c11d9b 542 if (RemainingDevicePath == NULL) {\r
e3dcffcc 543 //\r
f7c11d9b 544 // If RemainingDevicePath is NULL or is the End of Device Path Node\r
e3dcffcc 545 //\r
f7c11d9b 546 return EFI_SUCCESS;\r
95276127 547 }\r
e3dcffcc 548\r
e3dcffcc 549 //\r
f7c11d9b
RN
550 // This driver can only produce one child per serial port.\r
551 // Change its terminal type as remaining device path requests.\r
e3dcffcc 552 //\r
553 Status = gBS->OpenProtocolInformation (\r
554 Controller,\r
555 &gEfiSerialIoProtocolGuid,\r
556 &OpenInfoBuffer,\r
557 &EntryCount\r
558 );\r
559 if (!EFI_ERROR (Status)) {\r
f7c11d9b 560 Status = EFI_NOT_FOUND;\r
e3dcffcc 561 for (Index = 0; Index < EntryCount; Index++) {\r
562 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {\r
f7c11d9b
RN
563 Status = gBS->OpenProtocol (\r
564 OpenInfoBuffer[Index].ControllerHandle,\r
565 &gEfiSimpleTextInProtocolGuid,\r
1436aea4 566 (VOID **)&SimpleTextInput,\r
f7c11d9b
RN
567 This->DriverBindingHandle,\r
568 Controller,\r
569 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
570 );\r
571 if (!EFI_ERROR (Status)) {\r
572 TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (SimpleTextInput);\r
1436aea4 573 TerminalType = TerminalTypeFromGuid (&((VENDOR_DEVICE_PATH *)RemainingDevicePath)->Guid);\r
f7c11d9b
RN
574 ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));\r
575 if (TerminalDevice->TerminalType != TerminalType) {\r
576 Status = InitializeControllerNameTable (TerminalType, &ControllerNameTable);\r
577 if (!EFI_ERROR (Status)) {\r
578 StopTerminalStateMachine (TerminalDevice);\r
579 //\r
580 // Update the device path\r
581 //\r
582 Vendor = TerminalDevice->DevicePath;\r
583 Status = gBS->LocateDevicePath (&gEfiSerialIoProtocolGuid, &Vendor, &SerialIoHandle);\r
584 ASSERT_EFI_ERROR (Status);\r
1436aea4 585 CopyGuid (&((VENDOR_DEVICE_PATH *)Vendor)->Guid, mTerminalType[TerminalType]);\r
f7c11d9b
RN
586 Status = gBS->ReinstallProtocolInterface (\r
587 TerminalDevice->Handle,\r
588 &gEfiDevicePathProtocolGuid,\r
589 TerminalDevice->DevicePath,\r
590 TerminalDevice->DevicePath\r
591 );\r
592 if (!EFI_ERROR (Status)) {\r
593 TerminalDevice->TerminalType = TerminalType;\r
594 StartTerminalStateMachine (TerminalDevice);\r
595 FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);\r
596 TerminalDevice->ControllerNameTable = ControllerNameTable;\r
597 } else {\r
598 //\r
599 // Restore the device path on failure\r
600 //\r
1436aea4 601 CopyGuid (&((VENDOR_DEVICE_PATH *)Vendor)->Guid, mTerminalType[TerminalDevice->TerminalType]);\r
f7c11d9b
RN
602 FreeUnicodeStringTable (ControllerNameTable);\r
603 }\r
604 }\r
605 }\r
606 }\r
1436aea4 607\r
f7c11d9b 608 break;\r
e3dcffcc 609 }\r
610 }\r
1436aea4 611\r
e3dcffcc 612 FreePool (OpenInfoBuffer);\r
e3dcffcc 613 }\r
1436aea4 614\r
f7c11d9b
RN
615 return Status;\r
616 }\r
e3dcffcc 617\r
f7c11d9b
RN
618 //\r
619 // Initialize the Terminal Dev\r
620 //\r
621 TerminalDevice = AllocateCopyPool (sizeof (TERMINAL_DEV), &mTerminalDevTemplate);\r
622 if (TerminalDevice == NULL) {\r
623 Status = EFI_OUT_OF_RESOURCES;\r
624 goto CloseProtocols;\r
625 }\r
390b95a4 626\r
f7c11d9b 627 if (RemainingDevicePath == NULL) {\r
e3dcffcc 628 //\r
f7c11d9b 629 // If RemainingDevicePath is NULL, use default terminal type\r
e3dcffcc 630 //\r
f7c11d9b
RN
631 TerminalDevice->TerminalType = PcdGet8 (PcdDefaultTerminalType);\r
632 } else {\r
e3dcffcc 633 //\r
f7c11d9b 634 // End of Device Path Node is handled in above.\r
e3dcffcc 635 //\r
f7c11d9b 636 ASSERT (!IsDevicePathEnd (RemainingDevicePath));\r
95276127 637 //\r
f7c11d9b
RN
638 // If RemainingDevicePath isn't the End of Device Path Node,\r
639 // Use the RemainingDevicePath to determine the terminal type\r
95276127 640 //\r
1436aea4 641 TerminalDevice->TerminalType = TerminalTypeFromGuid (&((VENDOR_DEVICE_PATH *)RemainingDevicePath)->Guid);\r
f7c11d9b 642 }\r
1436aea4 643\r
f7c11d9b
RN
644 ASSERT (TerminalDevice->TerminalType < ARRAY_SIZE (mTerminalType));\r
645 TerminalDevice->SerialIo = SerialIo;\r
abef1c7a 646\r
f7c11d9b
RN
647 //\r
648 // Build the component name for the child device\r
649 //\r
650 Status = InitializeControllerNameTable (TerminalDevice->TerminalType, &TerminalDevice->ControllerNameTable);\r
651 if (EFI_ERROR (Status)) {\r
652 goto FreeResources;\r
653 }\r
abef1c7a 654\r
f7c11d9b
RN
655 //\r
656 // Build the device path for the child device\r
657 //\r
658 Status = SetTerminalDevicePath (TerminalDevice->TerminalType, ParentDevicePath, &TerminalDevice->DevicePath);\r
659 if (EFI_ERROR (Status)) {\r
660 goto FreeResources;\r
661 }\r
abef1c7a 662\r
f7c11d9b
RN
663 InitializeListHead (&TerminalDevice->NotifyList);\r
664 Status = gBS->CreateEvent (\r
665 EVT_NOTIFY_WAIT,\r
666 TPL_NOTIFY,\r
667 TerminalConInWaitForKeyEx,\r
668 TerminalDevice,\r
669 &TerminalDevice->SimpleInputEx.WaitForKeyEx\r
670 );\r
671 ASSERT_EFI_ERROR (Status);\r
47b612db 672\r
f7c11d9b
RN
673 Status = gBS->CreateEvent (\r
674 EVT_NOTIFY_WAIT,\r
675 TPL_NOTIFY,\r
676 TerminalConInWaitForKey,\r
677 TerminalDevice,\r
678 &TerminalDevice->SimpleInput.WaitForKey\r
679 );\r
680 ASSERT_EFI_ERROR (Status);\r
681 Status = gBS->CreateEvent (\r
682 EVT_NOTIFY_SIGNAL,\r
683 TPL_CALLBACK,\r
684 KeyNotifyProcessHandler,\r
685 TerminalDevice,\r
686 &TerminalDevice->KeyNotifyProcessEvent\r
687 );\r
688 ASSERT_EFI_ERROR (Status);\r
95276127 689\r
f7c11d9b
RN
690 //\r
691 // Allocates and initializes the FIFO buffer to be zero, used for accommodating\r
692 // the pre-read pending characters.\r
693 //\r
694 TerminalDevice->RawFiFo = AllocateZeroPool (sizeof (RAW_DATA_FIFO));\r
695 if (TerminalDevice->RawFiFo == NULL) {\r
696 goto FreeResources;\r
697 }\r
1436aea4 698\r
f7c11d9b
RN
699 TerminalDevice->UnicodeFiFo = AllocateZeroPool (sizeof (UNICODE_FIFO));\r
700 if (TerminalDevice->UnicodeFiFo == NULL) {\r
701 goto FreeResources;\r
702 }\r
1436aea4 703\r
f7c11d9b
RN
704 TerminalDevice->EfiKeyFiFo = AllocateZeroPool (sizeof (EFI_KEY_FIFO));\r
705 if (TerminalDevice->EfiKeyFiFo == NULL) {\r
706 goto FreeResources;\r
707 }\r
1436aea4 708\r
f7c11d9b
RN
709 TerminalDevice->EfiKeyFiFoForNotify = AllocateZeroPool (sizeof (EFI_KEY_FIFO));\r
710 if (TerminalDevice->EfiKeyFiFoForNotify == NULL) {\r
711 goto FreeResources;\r
95276127 712 }\r
95276127 713\r
3012ce5c 714 //\r
f7c11d9b 715 // Set the timeout value of serial buffer for keystroke response performance issue\r
3012ce5c 716 //\r
f7c11d9b 717 Mode = TerminalDevice->SerialIo->Mode;\r
3012ce5c 718\r
f7c11d9b
RN
719 SerialInTimeOut = 0;\r
720 if (Mode->BaudRate != 0) {\r
1436aea4 721 SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN)Mode->BaudRate;\r
f7c11d9b 722 }\r
95276127 723\r
f7c11d9b
RN
724 Status = TerminalDevice->SerialIo->SetAttributes (\r
725 TerminalDevice->SerialIo,\r
726 Mode->BaudRate,\r
727 Mode->ReceiveFifoDepth,\r
1436aea4
MK
728 (UINT32)SerialInTimeOut,\r
729 (EFI_PARITY_TYPE)(Mode->Parity),\r
730 (UINT8)Mode->DataBits,\r
731 (EFI_STOP_BITS_TYPE)(Mode->StopBits)\r
f7c11d9b
RN
732 );\r
733 if (EFI_ERROR (Status)) {\r
734 //\r
735 // if set attributes operation fails, invalidate\r
736 // the value of SerialInTimeOut,thus make it\r
737 // inconsistent with the default timeout value\r
738 // of serial buffer. This will invoke the recalculation\r
739 // in the readkeystroke routine.\r
740 //\r
741 TerminalDevice->SerialInTimeOut = 0;\r
e3dcffcc 742 } else {\r
f7c11d9b 743 TerminalDevice->SerialInTimeOut = SerialInTimeOut;\r
95276127 744 }\r
745\r
f7c11d9b 746 SimpleTextOutput = &TerminalDevice->SimpleTextOutput;\r
1436aea4 747 SimpleTextInput = &TerminalDevice->SimpleInput;\r
f7c11d9b 748\r
e3dcffcc 749 //\r
f7c11d9b 750 // Initialize SimpleTextOut instance\r
e3dcffcc 751 //\r
1436aea4 752 SimpleTextOutput->Mode = &TerminalDevice->SimpleTextOutputMode;\r
f7c11d9b 753 TerminalDevice->TerminalConsoleModeData = InitializeTerminalConsoleTextMode (\r
1436aea4
MK
754 &SimpleTextOutput->Mode->MaxMode\r
755 );\r
f7c11d9b
RN
756 if (TerminalDevice->TerminalConsoleModeData == NULL) {\r
757 goto FreeResources;\r
95276127 758 }\r
1436aea4 759\r
95276127 760 //\r
f7c11d9b 761 // For terminal devices, cursor is always visible\r
95276127 762 //\r
f7c11d9b 763 SimpleTextOutput->Mode->CursorVisible = TRUE;\r
1436aea4 764 Status = SimpleTextOutput->SetAttribute (SimpleTextOutput, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
f7c11d9b
RN
765 if (!EFI_ERROR (Status)) {\r
766 Status = SimpleTextOutput->Reset (SimpleTextOutput, FALSE);\r
767 }\r
1436aea4 768\r
f7c11d9b
RN
769 if (EFI_ERROR (Status)) {\r
770 goto ReportError;\r
95276127 771 }\r
f1aec6cc 772\r
95276127 773 //\r
f7c11d9b 774 // Initialize SimpleTextInput instance\r
95276127 775 //\r
f7c11d9b
RN
776 Status = SimpleTextInput->Reset (SimpleTextInput, FALSE);\r
777 if (EFI_ERROR (Status)) {\r
778 goto ReportError;\r
95276127 779 }\r
780\r
f7c11d9b
RN
781 Status = gBS->InstallMultipleProtocolInterfaces (\r
782 &TerminalDevice->Handle,\r
1436aea4
MK
783 &gEfiSimpleTextInProtocolGuid,\r
784 &TerminalDevice->SimpleInput,\r
785 &gEfiSimpleTextInputExProtocolGuid,\r
786 &TerminalDevice->SimpleInputEx,\r
787 &gEfiSimpleTextOutProtocolGuid,\r
788 &TerminalDevice->SimpleTextOutput,\r
789 &gEfiDevicePathProtocolGuid,\r
790 TerminalDevice->DevicePath,\r
f7c11d9b
RN
791 NULL\r
792 );\r
793 if (!EFI_ERROR (Status)) {\r
794 Status = gBS->OpenProtocol (\r
795 Controller,\r
796 &gEfiSerialIoProtocolGuid,\r
1436aea4 797 (VOID **)&TerminalDevice->SerialIo,\r
f7c11d9b
RN
798 This->DriverBindingHandle,\r
799 TerminalDevice->Handle,\r
800 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
e3dcffcc 801 );\r
f7c11d9b
RN
802 ASSERT_EFI_ERROR (Status);\r
803 StartTerminalStateMachine (TerminalDevice);\r
804 return Status;\r
e3dcffcc 805 }\r
95276127 806\r
95276127 807ReportError:\r
95276127 808 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
809 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
f9876ecf 810 (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),\r
f7c11d9b 811 ParentDevicePath\r
95276127 812 );\r
813\r
f7c11d9b
RN
814FreeResources:\r
815 ASSERT (TerminalDevice != NULL);\r
95276127 816\r
f7c11d9b
RN
817 if (TerminalDevice->SimpleInput.WaitForKey != NULL) {\r
818 gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);\r
819 }\r
1436aea4 820\r
f7c11d9b
RN
821 if (TerminalDevice->SimpleInputEx.WaitForKeyEx != NULL) {\r
822 gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);\r
823 }\r
1436aea4 824\r
f7c11d9b
RN
825 if (TerminalDevice->KeyNotifyProcessEvent != NULL) {\r
826 gBS->CloseEvent (TerminalDevice->KeyNotifyProcessEvent);\r
827 }\r
f0368006 828\r
f7c11d9b
RN
829 if (TerminalDevice->RawFiFo != NULL) {\r
830 FreePool (TerminalDevice->RawFiFo);\r
831 }\r
1436aea4 832\r
f7c11d9b
RN
833 if (TerminalDevice->UnicodeFiFo != NULL) {\r
834 FreePool (TerminalDevice->UnicodeFiFo);\r
835 }\r
1436aea4 836\r
f7c11d9b
RN
837 if (TerminalDevice->EfiKeyFiFo != NULL) {\r
838 FreePool (TerminalDevice->EfiKeyFiFo);\r
839 }\r
1436aea4 840\r
f7c11d9b
RN
841 if (TerminalDevice->EfiKeyFiFoForNotify != NULL) {\r
842 FreePool (TerminalDevice->EfiKeyFiFoForNotify);\r
843 }\r
95276127 844\r
f7c11d9b
RN
845 if (TerminalDevice->ControllerNameTable != NULL) {\r
846 FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);\r
847 }\r
66aa04e4 848\r
f7c11d9b
RN
849 if (TerminalDevice->DevicePath != NULL) {\r
850 FreePool (TerminalDevice->DevicePath);\r
851 }\r
66aa04e4 852\r
f7c11d9b
RN
853 if (TerminalDevice->TerminalConsoleModeData != NULL) {\r
854 FreePool (TerminalDevice->TerminalConsoleModeData);\r
855 }\r
95276127 856\r
f7c11d9b 857 FreePool (TerminalDevice);\r
95276127 858\r
f7c11d9b 859CloseProtocols:\r
79d07c66 860\r
f7c11d9b
RN
861 //\r
862 // Remove Parent Device Path from\r
863 // the Console Device Environment Variables\r
864 //\r
865 TerminalRemoveConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME, ParentDevicePath);\r
866 TerminalRemoveConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME, ParentDevicePath);\r
867 TerminalRemoveConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME, ParentDevicePath);\r
95276127 868\r
f7c11d9b
RN
869 Status = gBS->CloseProtocol (\r
870 Controller,\r
871 &gEfiSerialIoProtocolGuid,\r
872 This->DriverBindingHandle,\r
873 Controller\r
874 );\r
875 ASSERT_EFI_ERROR (Status);\r
95276127 876\r
f7c11d9b
RN
877 Status = gBS->CloseProtocol (\r
878 Controller,\r
879 &gEfiDevicePathProtocolGuid,\r
880 This->DriverBindingHandle,\r
881 Controller\r
882 );\r
883 ASSERT_EFI_ERROR (Status);\r
95276127 884 return Status;\r
885}\r
886\r
e49ef433 887/**\r
ab76200c 888 Stop this driver on Controller by closing Simple Text In, Simple Text\r
8fd98315 889 In Ex, Simple Text Out protocol, and removing parent device path from\r
677fdb90 890 Console Device Environment Variables.\r
e49ef433 891\r
8fd98315 892 @param This Protocol instance pointer.\r
ab76200c 893 @param Controller Handle of device to stop driver on\r
8fd98315 894 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of\r
895 children is zero stop the entire bus driver.\r
896 @param ChildHandleBuffer List of Child Handles to Stop.\r
e49ef433 897\r
ab76200c 898 @retval EFI_SUCCESS This driver is removed Controller.\r
8fd98315 899 @retval other This driver could not be removed from this device.\r
e49ef433 900\r
901**/\r
95276127 902EFI_STATUS\r
903EFIAPI\r
904TerminalDriverBindingStop (\r
1436aea4
MK
905 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
906 IN EFI_HANDLE Controller,\r
907 IN UINTN NumberOfChildren,\r
908 IN EFI_HANDLE *ChildHandleBuffer\r
95276127 909 )\r
95276127 910{\r
911 EFI_STATUS Status;\r
912 UINTN Index;\r
913 BOOLEAN AllChildrenStopped;\r
914 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;\r
915 TERMINAL_DEV *TerminalDevice;\r
916 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
917 EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
95276127 918\r
919 //\r
920 // Complete all outstanding transactions to Controller.\r
921 // Don't allow any new transaction to Controller to be started.\r
922 //\r
923 if (NumberOfChildren == 0) {\r
924 //\r
925 // Close the bus driver\r
926 //\r
927 Status = gBS->OpenProtocol (\r
928 Controller,\r
f7c11d9b 929 &gEfiDevicePathProtocolGuid,\r
1436aea4 930 (VOID **)&ParentDevicePath,\r
95276127 931 This->DriverBindingHandle,\r
932 Controller,\r
933 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
934 );\r
f7c11d9b 935 ASSERT_EFI_ERROR (Status);\r
95276127 936\r
f7c11d9b
RN
937 //\r
938 // Remove Parent Device Path from\r
939 // the Console Device Environment Variables\r
940 //\r
941 TerminalRemoveConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME, ParentDevicePath);\r
942 TerminalRemoveConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME, ParentDevicePath);\r
943 TerminalRemoveConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME, ParentDevicePath);\r
95276127 944\r
945 gBS->CloseProtocol (\r
1436aea4
MK
946 Controller,\r
947 &gEfiSerialIoProtocolGuid,\r
948 This->DriverBindingHandle,\r
949 Controller\r
950 );\r
95276127 951\r
952 gBS->CloseProtocol (\r
1436aea4
MK
953 Controller,\r
954 &gEfiDevicePathProtocolGuid,\r
955 This->DriverBindingHandle,\r
956 Controller\r
957 );\r
95276127 958\r
959 return EFI_SUCCESS;\r
960 }\r
961\r
962 AllChildrenStopped = TRUE;\r
963\r
964 for (Index = 0; Index < NumberOfChildren; Index++) {\r
95276127 965 Status = gBS->OpenProtocol (\r
966 ChildHandleBuffer[Index],\r
967 &gEfiSimpleTextOutProtocolGuid,\r
1436aea4 968 (VOID **)&SimpleTextOutput,\r
95276127 969 This->DriverBindingHandle,\r
970 ChildHandleBuffer[Index],\r
971 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
972 );\r
973 if (!EFI_ERROR (Status)) {\r
95276127 974 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);\r
975\r
976 gBS->CloseProtocol (\r
1436aea4
MK
977 Controller,\r
978 &gEfiSerialIoProtocolGuid,\r
979 This->DriverBindingHandle,\r
980 ChildHandleBuffer[Index]\r
981 );\r
95276127 982\r
983 Status = gBS->UninstallMultipleProtocolInterfaces (\r
984 ChildHandleBuffer[Index],\r
985 &gEfiSimpleTextInProtocolGuid,\r
986 &TerminalDevice->SimpleInput,\r
66aa04e4 987 &gEfiSimpleTextInputExProtocolGuid,\r
988 &TerminalDevice->SimpleInputEx,\r
95276127 989 &gEfiSimpleTextOutProtocolGuid,\r
990 &TerminalDevice->SimpleTextOutput,\r
991 &gEfiDevicePathProtocolGuid,\r
992 TerminalDevice->DevicePath,\r
993 NULL\r
994 );\r
995 if (EFI_ERROR (Status)) {\r
996 gBS->OpenProtocol (\r
1436aea4
MK
997 Controller,\r
998 &gEfiSerialIoProtocolGuid,\r
999 (VOID **)&SerialIo,\r
1000 This->DriverBindingHandle,\r
1001 ChildHandleBuffer[Index],\r
1002 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
1003 );\r
95276127 1004 } else {\r
0d8b3f81 1005 FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);\r
b7cf1c07 1006 StopTerminalStateMachine (TerminalDevice);\r
95276127 1007 gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);\r
66aa04e4 1008 gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);\r
47b612db 1009 gBS->CloseEvent (TerminalDevice->KeyNotifyProcessEvent);\r
66aa04e4 1010 TerminalFreeNotifyList (&TerminalDevice->NotifyList);\r
95276127 1011 FreePool (TerminalDevice->DevicePath);\r
0d8b3f81 1012 FreePool (TerminalDevice->TerminalConsoleModeData);\r
95276127 1013 FreePool (TerminalDevice);\r
1014 }\r
1015 }\r
1016\r
1017 if (EFI_ERROR (Status)) {\r
1018 AllChildrenStopped = FALSE;\r
1019 }\r
1020 }\r
1021\r
1022 if (!AllChildrenStopped) {\r
1023 return EFI_DEVICE_ERROR;\r
1024 }\r
1025\r
1026 return EFI_SUCCESS;\r
1027}\r
1028\r
b9c04b88
RN
1029/**\r
1030 Compare a device path data structure to that of all the nodes of a\r
1031 second device path instance.\r
1032\r
1033 @param Multi A pointer to a multi-instance device path data structure.\r
1034 @param Single A pointer to a single-instance device path data structure.\r
1035\r
1036 @retval TRUE If the Single is contained within Multi.\r
1037 @retval FALSE The Single is not match within Multi.\r
1038\r
1039**/\r
1040BOOLEAN\r
1041MatchDevicePaths (\r
1042 IN EFI_DEVICE_PATH_PROTOCOL *Multi,\r
1043 IN EFI_DEVICE_PATH_PROTOCOL *Single\r
1044 )\r
1045{\r
1046 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1047 EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;\r
1048 UINTN Size;\r
1049\r
1436aea4
MK
1050 DevicePath = Multi;\r
1051 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);\r
b9c04b88
RN
1052 //\r
1053 // Search for the match of 'Single' in 'Multi'\r
1054 //\r
1055 while (DevicePathInst != NULL) {\r
1056 //\r
1057 // If the single device path is found in multiple device paths,\r
1058 // return success\r
1059 //\r
1060 if (CompareMem (Single, DevicePathInst, Size) == 0) {\r
1061 FreePool (DevicePathInst);\r
1062 return TRUE;\r
1063 }\r
1064\r
1065 FreePool (DevicePathInst);\r
1066 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);\r
1067 }\r
1068\r
1069 return FALSE;\r
1070}\r
1071\r
8fd98315 1072/**\r
1073 Update terminal device path in Console Device Environment Variables.\r
1074\r
1075 @param VariableName The Console Device Environment Variable.\r
11baadb6 1076 @param ParentDevicePath The terminal device path to be updated.\r
8fd98315 1077\r
8fd98315 1078**/\r
95276127 1079VOID\r
1080TerminalUpdateConsoleDevVariable (\r
1081 IN CHAR16 *VariableName,\r
1082 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath\r
1083 )\r
1084{\r
1436aea4
MK
1085 EFI_STATUS Status;\r
1086 UINTN NameSize;\r
1087 UINTN VariableSize;\r
1088 TERMINAL_TYPE TerminalType;\r
1089 EFI_DEVICE_PATH_PROTOCOL *Variable;\r
1090 EFI_DEVICE_PATH_PROTOCOL *NewVariable;\r
1091 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
1092 EDKII_SET_VARIABLE_STATUS *SetVariableStatus;\r
95276127 1093\r
95276127 1094 //\r
1095 // Get global variable and its size according to the name given.\r
1096 //\r
1436aea4 1097 Status = GetEfiGlobalVariable2 (VariableName, (VOID **)&Variable, NULL);\r
b9c04b88
RN
1098 if (Status == EFI_NOT_FOUND) {\r
1099 Status = EFI_SUCCESS;\r
1100 Variable = NULL;\r
1101 }\r
1436aea4 1102\r
b9c04b88 1103 if (EFI_ERROR (Status)) {\r
e3dcffcc 1104 return;\r
1105 }\r
1106\r
95276127 1107 //\r
1108 // Append terminal device path onto the variable.\r
1109 //\r
f9163275 1110 for (TerminalType = 0; TerminalType < ARRAY_SIZE (mTerminalType); TerminalType++) {\r
95276127 1111 SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);\r
95276127 1112\r
1113 if (TempDevicePath != NULL) {\r
b9c04b88
RN
1114 if (!MatchDevicePaths (Variable, TempDevicePath)) {\r
1115 NewVariable = AppendDevicePathInstance (Variable, TempDevicePath);\r
1116 if (NewVariable != NULL) {\r
1117 if (Variable != NULL) {\r
1118 FreePool (Variable);\r
1119 }\r
1436aea4 1120\r
b9c04b88
RN
1121 Variable = NewVariable;\r
1122 }\r
1123 }\r
1124\r
95276127 1125 FreePool (TempDevicePath);\r
1126 }\r
95276127 1127 }\r
1128\r
1129 VariableSize = GetDevicePathSize (Variable);\r
1130\r
1131 Status = gRT->SetVariable (\r
1132 VariableName,\r
1133 &gEfiGlobalVariableGuid,\r
1134 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
1135 VariableSize,\r
1136 Variable\r
1137 );\r
5070befc
RN
1138\r
1139 if (EFI_ERROR (Status)) {\r
1436aea4 1140 NameSize = StrSize (VariableName);\r
5070befc
RN
1141 SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + VariableSize);\r
1142 if (SetVariableStatus != NULL) {\r
1143 CopyGuid (&SetVariableStatus->Guid, &gEfiGlobalVariableGuid);\r
1144 SetVariableStatus->NameSize = NameSize;\r
1145 SetVariableStatus->DataSize = VariableSize;\r
1146 SetVariableStatus->SetStatus = Status;\r
1147 SetVariableStatus->Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;\r
1436aea4
MK
1148 CopyMem (SetVariableStatus + 1, VariableName, NameSize);\r
1149 CopyMem (((UINT8 *)(SetVariableStatus + 1)) + NameSize, Variable, VariableSize);\r
5070befc
RN
1150\r
1151 REPORT_STATUS_CODE_EX (\r
1152 EFI_ERROR_CODE,\r
1153 PcdGet32 (PcdErrorCodeSetVariable),\r
1154 0,\r
1155 NULL,\r
1156 &gEdkiiStatusCodeDataTypeVariableGuid,\r
1157 SetVariableStatus,\r
1158 sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + VariableSize\r
1159 );\r
1160\r
1161 FreePool (SetVariableStatus);\r
1162 }\r
1163 }\r
1164\r
95276127 1165 FreePool (Variable);\r
1166\r
1436aea4 1167 return;\r
95276127 1168}\r
1169\r
e49ef433 1170/**\r
8fd98315 1171 Remove terminal device path from Console Device Environment Variables.\r
e49ef433 1172\r
8fd98315 1173 @param VariableName Console Device Environment Variables.\r
11baadb6 1174 @param ParentDevicePath The terminal device path to be updated.\r
e49ef433 1175\r
e49ef433 1176**/\r
95276127 1177VOID\r
1178TerminalRemoveConsoleDevVariable (\r
1179 IN CHAR16 *VariableName,\r
1180 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath\r
1181 )\r
95276127 1182{\r
1183 EFI_STATUS Status;\r
1184 BOOLEAN FoundOne;\r
1185 BOOLEAN Match;\r
1186 UINTN VariableSize;\r
1187 UINTN InstanceSize;\r
8ce87fff 1188 TERMINAL_TYPE TerminalType;\r
95276127 1189 EFI_DEVICE_PATH_PROTOCOL *Instance;\r
1190 EFI_DEVICE_PATH_PROTOCOL *Variable;\r
1191 EFI_DEVICE_PATH_PROTOCOL *OriginalVariable;\r
1192 EFI_DEVICE_PATH_PROTOCOL *NewVariable;\r
1193 EFI_DEVICE_PATH_PROTOCOL *SavedNewVariable;\r
1194 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
1195\r
1436aea4 1196 Instance = NULL;\r
95276127 1197\r
1198 //\r
1199 // Get global variable and its size according to the name given.\r
1200 //\r
1436aea4 1201 GetEfiGlobalVariable2 (VariableName, (VOID **)&Variable, NULL);\r
95276127 1202 if (Variable == NULL) {\r
1436aea4 1203 return;\r
95276127 1204 }\r
1205\r
1436aea4
MK
1206 FoundOne = FALSE;\r
1207 OriginalVariable = Variable;\r
1208 NewVariable = NULL;\r
95276127 1209\r
1210 //\r
1211 // Get first device path instance from Variable\r
1212 //\r
1213 Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);\r
1214 if (Instance == NULL) {\r
1215 FreePool (OriginalVariable);\r
1436aea4 1216 return;\r
95276127 1217 }\r
1436aea4 1218\r
95276127 1219 //\r
1220 // Loop through all the device path instances of Variable\r
1221 //\r
1222 do {\r
1223 //\r
1224 // Loop through all the terminal types that this driver supports\r
1225 //\r
1226 Match = FALSE;\r
f9163275 1227 for (TerminalType = 0; TerminalType < ARRAY_SIZE (mTerminalType); TerminalType++) {\r
95276127 1228 SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);\r
1229\r
1230 //\r
11baadb6 1231 // Compare the generated device path to the current device path instance\r
95276127 1232 //\r
1233 if (TempDevicePath != NULL) {\r
1234 if (CompareMem (Instance, TempDevicePath, InstanceSize) == 0) {\r
1436aea4
MK
1235 Match = TRUE;\r
1236 FoundOne = TRUE;\r
95276127 1237 }\r
1238\r
1239 FreePool (TempDevicePath);\r
1240 }\r
1241 }\r
1436aea4 1242\r
95276127 1243 //\r
1244 // If a match was not found, then keep the current device path instance\r
1245 //\r
1246 if (!Match) {\r
1436aea4
MK
1247 SavedNewVariable = NewVariable;\r
1248 NewVariable = AppendDevicePathInstance (NewVariable, Instance);\r
95276127 1249 if (SavedNewVariable != NULL) {\r
1250 FreePool (SavedNewVariable);\r
1251 }\r
1252 }\r
1436aea4 1253\r
95276127 1254 //\r
1255 // Get next device path instance from Variable\r
1256 //\r
1257 FreePool (Instance);\r
1258 Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);\r
1259 } while (Instance != NULL);\r
1260\r
1261 FreePool (OriginalVariable);\r
1262\r
1263 if (FoundOne) {\r
1264 VariableSize = GetDevicePathSize (NewVariable);\r
1265\r
1266 Status = gRT->SetVariable (\r
1267 VariableName,\r
1268 &gEfiGlobalVariableGuid,\r
1269 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
1270 VariableSize,\r
1271 NewVariable\r
1272 );\r
5070befc
RN
1273 //\r
1274 // Shrinking variable with existing variable driver implementation shouldn't fail.\r
1275 //\r
1276 ASSERT_EFI_ERROR (Status);\r
95276127 1277 }\r
1278\r
1279 if (NewVariable != NULL) {\r
1280 FreePool (NewVariable);\r
1281 }\r
1282\r
1436aea4 1283 return;\r
95276127 1284}\r
1285\r
8fd98315 1286/**\r
11baadb6 1287 Build terminal device path according to terminal type.\r
8fd98315 1288\r
1289 @param TerminalType The terminal type is PC ANSI, VT100, VT100+ or VT-UTF8.\r
11baadb6 1290 @param ParentDevicePath Parent device path.\r
8fd98315 1291 @param TerminalDevicePath Returned terminal device path, if building successfully.\r
1292\r
1293 @retval EFI_UNSUPPORTED Terminal does not belong to the supported type.\r
1294 @retval EFI_OUT_OF_RESOURCES Generate terminal device path failed.\r
1295 @retval EFI_SUCCESS Build terminal device path successfully.\r
1296\r
1297**/\r
95276127 1298EFI_STATUS\r
1299SetTerminalDevicePath (\r
1436aea4
MK
1300 IN TERMINAL_TYPE TerminalType,\r
1301 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
1302 OUT EFI_DEVICE_PATH_PROTOCOL **TerminalDevicePath\r
95276127 1303 )\r
1304{\r
1305 VENDOR_DEVICE_PATH Node;\r
1306\r
802c39b0 1307 ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));\r
95276127 1308 Node.Header.Type = MESSAGING_DEVICE_PATH;\r
1309 Node.Header.SubType = MSG_VENDOR_DP;\r
178b6b5d 1310 SetDevicePathNodeLength (&Node.Header, sizeof (VENDOR_DEVICE_PATH));\r
802c39b0 1311 CopyGuid (&Node.Guid, mTerminalType[TerminalType]);\r
ab76200c 1312\r
95276127 1313 //\r
ab76200c 1314 // Append the terminal node onto parent device path\r
95276127 1315 // to generate a complete terminal device path.\r
1316 //\r
1317 *TerminalDevicePath = AppendDevicePathNode (\r
1318 ParentDevicePath,\r
1436aea4 1319 (EFI_DEVICE_PATH_PROTOCOL *)&Node\r
95276127 1320 );\r
1321 if (*TerminalDevicePath == NULL) {\r
1322 return EFI_OUT_OF_RESOURCES;\r
1323 }\r
1324\r
1325 return EFI_SUCCESS;\r
1326}\r
1327\r
97a079ed
A
1328/**\r
1329 The user Entry Point for module Terminal. The user code starts with this function.\r
1330\r
ab76200c 1331 @param ImageHandle The firmware allocated handle for the EFI image.\r
1332 @param SystemTable A pointer to the EFI System Table.\r
fb0b259e 1333\r
97a079ed
A
1334 @retval EFI_SUCCESS The entry point is executed successfully.\r
1335 @retval other Some error occurs when executing this entry point.\r
1336\r
1337**/\r
1338EFI_STATUS\r
1339EFIAPI\r
1436aea4
MK
1340InitializeTerminal (\r
1341 IN EFI_HANDLE ImageHandle,\r
1342 IN EFI_SYSTEM_TABLE *SystemTable\r
97a079ed
A
1343 )\r
1344{\r
1436aea4 1345 EFI_STATUS Status;\r
97a079ed
A
1346\r
1347 //\r
1348 // Install driver model protocol(s).\r
1349 //\r
5bca971e 1350 Status = EfiLibInstallDriverBindingComponentName2 (\r
97a079ed
A
1351 ImageHandle,\r
1352 SystemTable,\r
1353 &gTerminalDriverBinding,\r
1354 ImageHandle,\r
1355 &gTerminalComponentName,\r
5bca971e 1356 &gTerminalComponentName2\r
97a079ed
A
1357 );\r
1358 ASSERT_EFI_ERROR (Status);\r
1359\r
97a079ed
A
1360 return Status;\r
1361}\r
f1aec6cc 1362\r
1363/**\r
1364 Check if the device supports hot-plug through its device path.\r
1365\r
1366 This function could be updated to check more types of Hot Plug devices.\r
1367 Currently, it checks USB and PCCard device.\r
1368\r
1369 @param DevicePath Pointer to device's device path.\r
1370\r
1371 @retval TRUE The devcie is a hot-plug device\r
1372 @retval FALSE The devcie is not a hot-plug device.\r
1373\r
1374**/\r
1375BOOLEAN\r
1376IsHotPlugDevice (\r
1436aea4 1377 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
f1aec6cc 1378 )\r
1379{\r
1436aea4 1380 EFI_DEVICE_PATH_PROTOCOL *CheckDevicePath;\r
f1aec6cc 1381\r
1382 CheckDevicePath = DevicePath;\r
1383 while (!IsDevicePathEnd (CheckDevicePath)) {\r
1384 //\r
1385 // Check device whether is hot plug device or not throught Device Path\r
e3dcffcc 1386 //\r
f1aec6cc 1387 if ((DevicePathType (CheckDevicePath) == MESSAGING_DEVICE_PATH) &&\r
1436aea4
MK
1388 ((DevicePathSubType (CheckDevicePath) == MSG_USB_DP) ||\r
1389 (DevicePathSubType (CheckDevicePath) == MSG_USB_CLASS_DP) ||\r
1390 (DevicePathSubType (CheckDevicePath) == MSG_USB_WWID_DP)))\r
1391 {\r
f1aec6cc 1392 //\r
1393 // If Device is USB device\r
1394 //\r
1395 return TRUE;\r
1396 }\r
1436aea4 1397\r
f1aec6cc 1398 if ((DevicePathType (CheckDevicePath) == HARDWARE_DEVICE_PATH) &&\r
1436aea4
MK
1399 (DevicePathSubType (CheckDevicePath) == HW_PCCARD_DP))\r
1400 {\r
f1aec6cc 1401 //\r
1402 // If Device is PCCard\r
1403 //\r
1404 return TRUE;\r
1405 }\r
e3dcffcc 1406\r
f1aec6cc 1407 CheckDevicePath = NextDevicePathNode (CheckDevicePath);\r
1408 }\r
1409\r
1410 return FALSE;\r
1411}\r