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