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