]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
MdeModulePkg/Terminal: Check status of OpenProtocol in BindingStart
[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
ebafede9 5Copyright (c) 2006 - 2018, 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
390b95a4
RN
321 TextModeData = AllocateCopyPool (sizeof (mTerminalConsoleModeData), mTerminalConsoleModeData);\r
322 if (TextModeData == NULL) {\r
323 return NULL;\r
79d07c66 324 }\r
390b95a4
RN
325 *TextModeCount = ARRAY_SIZE (mTerminalConsoleModeData);\r
326\r
79d07c66 327 DEBUG_CODE (\r
390b95a4
RN
328 INT32 Index;\r
329 for (Index = 0; Index < *TextModeCount; Index++) {\r
330 DEBUG ((DEBUG_INFO, "Terminal - Mode %d, Column = %d, Row = %d\n",\r
331 Index, TextModeData[Index].Columns, TextModeData[Index].Rows));\r
79d07c66 332 }\r
333 );\r
390b95a4 334 return TextModeData;\r
79d07c66 335}\r
e3dcffcc 336\r
b7cf1c07
RN
337/**\r
338 Stop the terminal state machine.\r
339\r
340 @param TerminalDevice The terminal device.\r
341**/\r
342VOID\r
343StopTerminalStateMachine (\r
344 TERMINAL_DEV *TerminalDevice\r
345 )\r
346{\r
347 EFI_TPL OriginalTpl;\r
348\r
349 OriginalTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
350\r
351 gBS->CloseEvent (TerminalDevice->TimerEvent);\r
352 gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);\r
353\r
354 gBS->RestoreTPL (OriginalTpl);\r
355}\r
356\r
357/**\r
358 Start the terminal state machine.\r
359\r
360 @param TerminalDevice The terminal device.\r
361**/\r
362VOID\r
363StartTerminalStateMachine (\r
364 TERMINAL_DEV *TerminalDevice\r
365 )\r
366{\r
367 EFI_STATUS Status;\r
368 Status = gBS->CreateEvent (\r
369 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
370 TPL_NOTIFY,\r
371 TerminalConInTimerHandler,\r
372 TerminalDevice,\r
373 &TerminalDevice->TimerEvent\r
374 );\r
375 ASSERT_EFI_ERROR (Status);\r
376\r
377 Status = gBS->SetTimer (\r
378 TerminalDevice->TimerEvent,\r
379 TimerPeriodic,\r
380 KEYBOARD_TIMER_INTERVAL\r
381 );\r
382 ASSERT_EFI_ERROR (Status);\r
383\r
384 Status = gBS->CreateEvent (\r
385 EVT_TIMER,\r
386 TPL_CALLBACK,\r
387 NULL,\r
388 NULL,\r
389 &TerminalDevice->TwoSecondTimeOut\r
390 );\r
391 ASSERT_EFI_ERROR (Status);\r
392}\r
393\r
fa3f99e5
RN
394/**\r
395 Initialize the controller name table.\r
396\r
397 @param TerminalType The terminal type.\r
398 @param ControllerNameTable The controller name table.\r
399\r
400 @retval EFI_SUCCESS The controller name table is initialized successfully.\r
401 @retval others Return status of AddUnicodeString2 ().\r
402**/\r
403EFI_STATUS\r
404InitializeControllerNameTable (\r
405 TERMINAL_TYPE TerminalType,\r
406 EFI_UNICODE_STRING_TABLE **ControllerNameTable\r
407)\r
408{\r
409 EFI_STATUS Status;\r
410 EFI_UNICODE_STRING_TABLE *Table;\r
411\r
412 ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));\r
413 Table = NULL;\r
414 Status = AddUnicodeString2 (\r
415 "eng",\r
416 gTerminalComponentName.SupportedLanguages,\r
417 &Table,\r
418 mSerialConsoleNames[TerminalType],\r
419 TRUE\r
420 );\r
421 if (!EFI_ERROR (Status)) {\r
422 Status = AddUnicodeString2 (\r
423 "en",\r
424 gTerminalComponentName2.SupportedLanguages,\r
425 &Table,\r
426 mSerialConsoleNames[TerminalType],\r
427 FALSE\r
428 );\r
429 if (EFI_ERROR (Status)) {\r
430 FreeUnicodeStringTable (Table);\r
431 }\r
432 }\r
433 if (!EFI_ERROR (Status)) {\r
434 *ControllerNameTable = Table;\r
435 }\r
436 return Status;\r
437}\r
438\r
e49ef433 439/**\r
ab76200c 440 Start this driver on Controller by opening a Serial IO protocol,\r
8fd98315 441 reading Device Path, and creating a child handle with a Simple Text In,\r
442 Simple Text In Ex and Simple Text Out protocol, and device path protocol.\r
443 And store Console Device Environment Variables.\r
e49ef433 444\r
8fd98315 445 @param This Protocol instance pointer.\r
ab76200c 446 @param Controller Handle of device to bind driver to\r
8fd98315 447 @param RemainingDevicePath Optional parameter use to pick a specific child\r
448 device to start.\r
e49ef433 449\r
ab76200c 450 @retval EFI_SUCCESS This driver is added to Controller.\r
451 @retval EFI_ALREADY_STARTED This driver is already running on Controller.\r
452 @retval other This driver does not support this device.\r
e49ef433 453\r
454**/\r
95276127 455EFI_STATUS\r
456EFIAPI\r
457TerminalDriverBindingStart (\r
458 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
459 IN EFI_HANDLE Controller,\r
460 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
461 )\r
95276127 462{\r
463 EFI_STATUS Status;\r
464 EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
465 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
f7c11d9b
RN
466 EFI_DEVICE_PATH_PROTOCOL *Vendor;\r
467 EFI_HANDLE SerialIoHandle;\r
95276127 468 EFI_SERIAL_IO_MODE *Mode;\r
469 UINTN SerialInTimeOut;\r
470 TERMINAL_DEV *TerminalDevice;\r
f7c11d9b 471 UINT8 TerminalType;\r
95276127 472 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;\r
473 UINTN EntryCount;\r
474 UINTN Index;\r
c4f9201e 475 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;\r
e3dcffcc 476 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextInput;\r
f7c11d9b
RN
477 EFI_UNICODE_STRING_TABLE *ControllerNameTable;\r
478\r
95276127 479 //\r
480 // Get the Device Path Protocol to build the device path of the child device\r
481 //\r
482 Status = gBS->OpenProtocol (\r
483 Controller,\r
484 &gEfiDevicePathProtocolGuid,\r
485 (VOID **) &ParentDevicePath,\r
486 This->DriverBindingHandle,\r
487 Controller,\r
488 EFI_OPEN_PROTOCOL_BY_DRIVER\r
489 );\r
f7c11d9b 490 ASSERT ((Status == EFI_SUCCESS) || (Status == EFI_ALREADY_STARTED));\r
ebafede9
RN
491 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
492 return Status;\r
493 }\r
95276127 494\r
495 //\r
496 // Open the Serial I/O Protocol BY_DRIVER. It might already be started.\r
497 //\r
498 Status = gBS->OpenProtocol (\r
499 Controller,\r
500 &gEfiSerialIoProtocolGuid,\r
501 (VOID **) &SerialIo,\r
502 This->DriverBindingHandle,\r
503 Controller,\r
504 EFI_OPEN_PROTOCOL_BY_DRIVER\r
505 );\r
f7c11d9b 506 ASSERT ((Status == EFI_SUCCESS) || (Status == EFI_ALREADY_STARTED));\r
ebafede9
RN
507 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
508 return Status;\r
509 }\r
95276127 510\r
f7c11d9b 511 if (!IsHotPlugDevice (ParentDevicePath)) {\r
95276127 512 //\r
f7c11d9b
RN
513 // if the serial device is a hot plug device, do not update the\r
514 // ConInDev, ConOutDev, and StdErrDev variables.\r
95276127 515 //\r
f7c11d9b
RN
516 TerminalUpdateConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME, ParentDevicePath);\r
517 TerminalUpdateConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME, ParentDevicePath);\r
518 TerminalUpdateConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME, ParentDevicePath);\r
95276127 519 }\r
e3dcffcc 520\r
95276127 521 //\r
f7c11d9b 522 // Do not create any child for END remaining device path.\r
95276127 523 //\r
f7c11d9b
RN
524 if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) {\r
525 return EFI_SUCCESS;\r
526 }\r
95276127 527\r
f7c11d9b
RN
528 if (Status == EFI_ALREADY_STARTED) {\r
529\r
530 if (RemainingDevicePath == NULL) {\r
e3dcffcc 531 //\r
f7c11d9b 532 // If RemainingDevicePath is NULL or is the End of Device Path Node\r
e3dcffcc 533 //\r
f7c11d9b 534 return EFI_SUCCESS;\r
95276127 535 }\r
e3dcffcc 536\r
e3dcffcc 537 //\r
f7c11d9b
RN
538 // This driver can only produce one child per serial port.\r
539 // Change its terminal type as remaining device path requests.\r
e3dcffcc 540 //\r
541 Status = gBS->OpenProtocolInformation (\r
542 Controller,\r
543 &gEfiSerialIoProtocolGuid,\r
544 &OpenInfoBuffer,\r
545 &EntryCount\r
546 );\r
547 if (!EFI_ERROR (Status)) {\r
f7c11d9b 548 Status = EFI_NOT_FOUND;\r
e3dcffcc 549 for (Index = 0; Index < EntryCount; Index++) {\r
550 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {\r
f7c11d9b
RN
551 Status = gBS->OpenProtocol (\r
552 OpenInfoBuffer[Index].ControllerHandle,\r
553 &gEfiSimpleTextInProtocolGuid,\r
554 (VOID **) &SimpleTextInput,\r
555 This->DriverBindingHandle,\r
556 Controller,\r
557 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
558 );\r
559 if (!EFI_ERROR (Status)) {\r
560 TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (SimpleTextInput);\r
561 TerminalType = TerminalTypeFromGuid (&((VENDOR_DEVICE_PATH *) RemainingDevicePath)->Guid);\r
562 ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));\r
563 if (TerminalDevice->TerminalType != TerminalType) {\r
564 Status = InitializeControllerNameTable (TerminalType, &ControllerNameTable);\r
565 if (!EFI_ERROR (Status)) {\r
566 StopTerminalStateMachine (TerminalDevice);\r
567 //\r
568 // Update the device path\r
569 //\r
570 Vendor = TerminalDevice->DevicePath;\r
571 Status = gBS->LocateDevicePath (&gEfiSerialIoProtocolGuid, &Vendor, &SerialIoHandle);\r
572 ASSERT_EFI_ERROR (Status);\r
573 CopyGuid (&((VENDOR_DEVICE_PATH *) Vendor)->Guid, mTerminalType[TerminalType]);\r
574 Status = gBS->ReinstallProtocolInterface (\r
575 TerminalDevice->Handle,\r
576 &gEfiDevicePathProtocolGuid,\r
577 TerminalDevice->DevicePath,\r
578 TerminalDevice->DevicePath\r
579 );\r
580 if (!EFI_ERROR (Status)) {\r
581 TerminalDevice->TerminalType = TerminalType;\r
582 StartTerminalStateMachine (TerminalDevice);\r
583 FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);\r
584 TerminalDevice->ControllerNameTable = ControllerNameTable;\r
585 } else {\r
586 //\r
587 // Restore the device path on failure\r
588 //\r
589 CopyGuid (&((VENDOR_DEVICE_PATH *) Vendor)->Guid, mTerminalType[TerminalDevice->TerminalType]);\r
590 FreeUnicodeStringTable (ControllerNameTable);\r
591 }\r
592 }\r
593 }\r
594 }\r
595 break;\r
e3dcffcc 596 }\r
597 }\r
e3dcffcc 598 FreePool (OpenInfoBuffer);\r
e3dcffcc 599 }\r
f7c11d9b
RN
600 return Status;\r
601 }\r
e3dcffcc 602\r
f7c11d9b
RN
603 //\r
604 // Initialize the Terminal Dev\r
605 //\r
606 TerminalDevice = AllocateCopyPool (sizeof (TERMINAL_DEV), &mTerminalDevTemplate);\r
607 if (TerminalDevice == NULL) {\r
608 Status = EFI_OUT_OF_RESOURCES;\r
609 goto CloseProtocols;\r
610 }\r
390b95a4 611\r
f7c11d9b 612 if (RemainingDevicePath == NULL) {\r
e3dcffcc 613 //\r
f7c11d9b 614 // If RemainingDevicePath is NULL, use default terminal type\r
e3dcffcc 615 //\r
f7c11d9b
RN
616 TerminalDevice->TerminalType = PcdGet8 (PcdDefaultTerminalType);\r
617 } else {\r
e3dcffcc 618 //\r
f7c11d9b 619 // End of Device Path Node is handled in above.\r
e3dcffcc 620 //\r
f7c11d9b 621 ASSERT (!IsDevicePathEnd (RemainingDevicePath));\r
95276127 622 //\r
f7c11d9b
RN
623 // If RemainingDevicePath isn't the End of Device Path Node,\r
624 // Use the RemainingDevicePath to determine the terminal type\r
95276127 625 //\r
f7c11d9b
RN
626 TerminalDevice->TerminalType = TerminalTypeFromGuid (&((VENDOR_DEVICE_PATH *) RemainingDevicePath)->Guid);\r
627 }\r
628 ASSERT (TerminalDevice->TerminalType < ARRAY_SIZE (mTerminalType));\r
629 TerminalDevice->SerialIo = SerialIo;\r
abef1c7a 630\r
f7c11d9b
RN
631 //\r
632 // Build the component name for the child device\r
633 //\r
634 Status = InitializeControllerNameTable (TerminalDevice->TerminalType, &TerminalDevice->ControllerNameTable);\r
635 if (EFI_ERROR (Status)) {\r
636 goto FreeResources;\r
637 }\r
abef1c7a 638\r
f7c11d9b
RN
639 //\r
640 // Build the device path for the child device\r
641 //\r
642 Status = SetTerminalDevicePath (TerminalDevice->TerminalType, ParentDevicePath, &TerminalDevice->DevicePath);\r
643 if (EFI_ERROR (Status)) {\r
644 goto FreeResources;\r
645 }\r
abef1c7a 646\r
f7c11d9b
RN
647 InitializeListHead (&TerminalDevice->NotifyList);\r
648 Status = gBS->CreateEvent (\r
649 EVT_NOTIFY_WAIT,\r
650 TPL_NOTIFY,\r
651 TerminalConInWaitForKeyEx,\r
652 TerminalDevice,\r
653 &TerminalDevice->SimpleInputEx.WaitForKeyEx\r
654 );\r
655 ASSERT_EFI_ERROR (Status);\r
47b612db 656\r
f7c11d9b
RN
657 Status = gBS->CreateEvent (\r
658 EVT_NOTIFY_WAIT,\r
659 TPL_NOTIFY,\r
660 TerminalConInWaitForKey,\r
661 TerminalDevice,\r
662 &TerminalDevice->SimpleInput.WaitForKey\r
663 );\r
664 ASSERT_EFI_ERROR (Status);\r
665 Status = gBS->CreateEvent (\r
666 EVT_NOTIFY_SIGNAL,\r
667 TPL_CALLBACK,\r
668 KeyNotifyProcessHandler,\r
669 TerminalDevice,\r
670 &TerminalDevice->KeyNotifyProcessEvent\r
671 );\r
672 ASSERT_EFI_ERROR (Status);\r
95276127 673\r
f7c11d9b
RN
674 //\r
675 // Allocates and initializes the FIFO buffer to be zero, used for accommodating\r
676 // the pre-read pending characters.\r
677 //\r
678 TerminalDevice->RawFiFo = AllocateZeroPool (sizeof (RAW_DATA_FIFO));\r
679 if (TerminalDevice->RawFiFo == NULL) {\r
680 goto FreeResources;\r
681 }\r
682 TerminalDevice->UnicodeFiFo = AllocateZeroPool (sizeof (UNICODE_FIFO));\r
683 if (TerminalDevice->UnicodeFiFo == NULL) {\r
684 goto FreeResources;\r
685 }\r
686 TerminalDevice->EfiKeyFiFo = AllocateZeroPool (sizeof (EFI_KEY_FIFO));\r
687 if (TerminalDevice->EfiKeyFiFo == NULL) {\r
688 goto FreeResources;\r
689 }\r
690 TerminalDevice->EfiKeyFiFoForNotify = AllocateZeroPool (sizeof (EFI_KEY_FIFO));\r
691 if (TerminalDevice->EfiKeyFiFoForNotify == NULL) {\r
692 goto FreeResources;\r
95276127 693 }\r
95276127 694\r
3012ce5c 695 //\r
f7c11d9b 696 // Set the timeout value of serial buffer for keystroke response performance issue\r
3012ce5c 697 //\r
f7c11d9b 698 Mode = TerminalDevice->SerialIo->Mode;\r
3012ce5c 699\r
f7c11d9b
RN
700 SerialInTimeOut = 0;\r
701 if (Mode->BaudRate != 0) {\r
702 SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate;\r
703 }\r
95276127 704\r
f7c11d9b
RN
705 Status = TerminalDevice->SerialIo->SetAttributes (\r
706 TerminalDevice->SerialIo,\r
707 Mode->BaudRate,\r
708 Mode->ReceiveFifoDepth,\r
709 (UINT32) SerialInTimeOut,\r
710 (EFI_PARITY_TYPE) (Mode->Parity),\r
711 (UINT8) Mode->DataBits,\r
712 (EFI_STOP_BITS_TYPE) (Mode->StopBits)\r
713 );\r
714 if (EFI_ERROR (Status)) {\r
715 //\r
716 // if set attributes operation fails, invalidate\r
717 // the value of SerialInTimeOut,thus make it\r
718 // inconsistent with the default timeout value\r
719 // of serial buffer. This will invoke the recalculation\r
720 // in the readkeystroke routine.\r
721 //\r
722 TerminalDevice->SerialInTimeOut = 0;\r
e3dcffcc 723 } else {\r
f7c11d9b 724 TerminalDevice->SerialInTimeOut = SerialInTimeOut;\r
95276127 725 }\r
726\r
f7c11d9b
RN
727 SimpleTextOutput = &TerminalDevice->SimpleTextOutput;\r
728 SimpleTextInput = &TerminalDevice->SimpleInput;\r
729\r
e3dcffcc 730 //\r
f7c11d9b 731 // Initialize SimpleTextOut instance\r
e3dcffcc 732 //\r
f7c11d9b
RN
733 SimpleTextOutput->Mode = &TerminalDevice->SimpleTextOutputMode;\r
734 TerminalDevice->TerminalConsoleModeData = InitializeTerminalConsoleTextMode (\r
735 &SimpleTextOutput->Mode->MaxMode\r
736 );\r
737 if (TerminalDevice->TerminalConsoleModeData == NULL) {\r
738 goto FreeResources;\r
95276127 739 }\r
95276127 740 //\r
f7c11d9b 741 // For terminal devices, cursor is always visible\r
95276127 742 //\r
f7c11d9b
RN
743 SimpleTextOutput->Mode->CursorVisible = TRUE;\r
744 Status = SimpleTextOutput->SetAttribute (SimpleTextOutput, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
745 if (!EFI_ERROR (Status)) {\r
746 Status = SimpleTextOutput->Reset (SimpleTextOutput, FALSE);\r
747 }\r
748 if (EFI_ERROR (Status)) {\r
749 goto ReportError;\r
95276127 750 }\r
f1aec6cc 751\r
95276127 752 //\r
f7c11d9b 753 // Initialize SimpleTextInput instance\r
95276127 754 //\r
f7c11d9b
RN
755 Status = SimpleTextInput->Reset (SimpleTextInput, FALSE);\r
756 if (EFI_ERROR (Status)) {\r
757 goto ReportError;\r
95276127 758 }\r
759\r
f7c11d9b
RN
760 Status = gBS->InstallMultipleProtocolInterfaces (\r
761 &TerminalDevice->Handle,\r
762 &gEfiSimpleTextInProtocolGuid, &TerminalDevice->SimpleInput,\r
763 &gEfiSimpleTextInputExProtocolGuid, &TerminalDevice->SimpleInputEx,\r
764 &gEfiSimpleTextOutProtocolGuid, &TerminalDevice->SimpleTextOutput,\r
765 &gEfiDevicePathProtocolGuid, TerminalDevice->DevicePath,\r
766 NULL\r
767 );\r
768 if (!EFI_ERROR (Status)) {\r
769 Status = gBS->OpenProtocol (\r
770 Controller,\r
771 &gEfiSerialIoProtocolGuid,\r
772 (VOID **) &TerminalDevice->SerialIo,\r
773 This->DriverBindingHandle,\r
774 TerminalDevice->Handle,\r
775 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
e3dcffcc 776 );\r
f7c11d9b
RN
777 ASSERT_EFI_ERROR (Status);\r
778 StartTerminalStateMachine (TerminalDevice);\r
779 return Status;\r
e3dcffcc 780 }\r
95276127 781\r
95276127 782ReportError:\r
95276127 783 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
784 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
f9876ecf 785 (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),\r
f7c11d9b 786 ParentDevicePath\r
95276127 787 );\r
788\r
f7c11d9b
RN
789FreeResources:\r
790 ASSERT (TerminalDevice != NULL);\r
95276127 791\r
f7c11d9b
RN
792 if (TerminalDevice->SimpleInput.WaitForKey != NULL) {\r
793 gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);\r
794 }\r
795 if (TerminalDevice->SimpleInputEx.WaitForKeyEx != NULL) {\r
796 gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);\r
797 }\r
798 if (TerminalDevice->KeyNotifyProcessEvent != NULL) {\r
799 gBS->CloseEvent (TerminalDevice->KeyNotifyProcessEvent);\r
800 }\r
f0368006 801\r
f7c11d9b
RN
802 if (TerminalDevice->RawFiFo != NULL) {\r
803 FreePool (TerminalDevice->RawFiFo);\r
804 }\r
805 if (TerminalDevice->UnicodeFiFo != NULL) {\r
806 FreePool (TerminalDevice->UnicodeFiFo);\r
807 }\r
808 if (TerminalDevice->EfiKeyFiFo != NULL) {\r
809 FreePool (TerminalDevice->EfiKeyFiFo);\r
810 }\r
811 if (TerminalDevice->EfiKeyFiFoForNotify != NULL) {\r
812 FreePool (TerminalDevice->EfiKeyFiFoForNotify);\r
813 }\r
95276127 814\r
f7c11d9b
RN
815 if (TerminalDevice->ControllerNameTable != NULL) {\r
816 FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);\r
817 }\r
66aa04e4 818\r
f7c11d9b
RN
819 if (TerminalDevice->DevicePath != NULL) {\r
820 FreePool (TerminalDevice->DevicePath);\r
821 }\r
66aa04e4 822\r
f7c11d9b
RN
823 if (TerminalDevice->TerminalConsoleModeData != NULL) {\r
824 FreePool (TerminalDevice->TerminalConsoleModeData);\r
825 }\r
95276127 826\r
f7c11d9b 827 FreePool (TerminalDevice);\r
95276127 828\r
f7c11d9b 829CloseProtocols:\r
79d07c66 830\r
f7c11d9b
RN
831 //\r
832 // Remove Parent Device Path from\r
833 // the Console Device Environment Variables\r
834 //\r
835 TerminalRemoveConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME, ParentDevicePath);\r
836 TerminalRemoveConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME, ParentDevicePath);\r
837 TerminalRemoveConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME, ParentDevicePath);\r
95276127 838\r
f7c11d9b
RN
839 Status = gBS->CloseProtocol (\r
840 Controller,\r
841 &gEfiSerialIoProtocolGuid,\r
842 This->DriverBindingHandle,\r
843 Controller\r
844 );\r
845 ASSERT_EFI_ERROR (Status);\r
95276127 846\r
f7c11d9b
RN
847 Status = gBS->CloseProtocol (\r
848 Controller,\r
849 &gEfiDevicePathProtocolGuid,\r
850 This->DriverBindingHandle,\r
851 Controller\r
852 );\r
853 ASSERT_EFI_ERROR (Status);\r
95276127 854 return Status;\r
855}\r
856\r
e49ef433 857/**\r
ab76200c 858 Stop this driver on Controller by closing Simple Text In, Simple Text\r
8fd98315 859 In Ex, Simple Text Out protocol, and removing parent device path from\r
677fdb90 860 Console Device Environment Variables.\r
e49ef433 861\r
8fd98315 862 @param This Protocol instance pointer.\r
ab76200c 863 @param Controller Handle of device to stop driver on\r
8fd98315 864 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of\r
865 children is zero stop the entire bus driver.\r
866 @param ChildHandleBuffer List of Child Handles to Stop.\r
e49ef433 867\r
ab76200c 868 @retval EFI_SUCCESS This driver is removed Controller.\r
8fd98315 869 @retval other This driver could not be removed from this device.\r
e49ef433 870\r
871**/\r
95276127 872EFI_STATUS\r
873EFIAPI\r
874TerminalDriverBindingStop (\r
875 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
876 IN EFI_HANDLE Controller,\r
877 IN UINTN NumberOfChildren,\r
878 IN EFI_HANDLE *ChildHandleBuffer\r
879 )\r
95276127 880{\r
881 EFI_STATUS Status;\r
882 UINTN Index;\r
883 BOOLEAN AllChildrenStopped;\r
884 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;\r
885 TERMINAL_DEV *TerminalDevice;\r
886 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
887 EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
95276127 888\r
889 //\r
890 // Complete all outstanding transactions to Controller.\r
891 // Don't allow any new transaction to Controller to be started.\r
892 //\r
893 if (NumberOfChildren == 0) {\r
894 //\r
895 // Close the bus driver\r
896 //\r
897 Status = gBS->OpenProtocol (\r
898 Controller,\r
f7c11d9b 899 &gEfiDevicePathProtocolGuid,\r
95276127 900 (VOID **) &ParentDevicePath,\r
901 This->DriverBindingHandle,\r
902 Controller,\r
903 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
904 );\r
f7c11d9b 905 ASSERT_EFI_ERROR (Status);\r
95276127 906\r
f7c11d9b
RN
907 //\r
908 // Remove Parent Device Path from\r
909 // the Console Device Environment Variables\r
910 //\r
911 TerminalRemoveConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME, ParentDevicePath);\r
912 TerminalRemoveConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME, ParentDevicePath);\r
913 TerminalRemoveConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME, ParentDevicePath);\r
95276127 914\r
915 gBS->CloseProtocol (\r
916 Controller,\r
917 &gEfiSerialIoProtocolGuid,\r
918 This->DriverBindingHandle,\r
919 Controller\r
920 );\r
921\r
922 gBS->CloseProtocol (\r
923 Controller,\r
924 &gEfiDevicePathProtocolGuid,\r
925 This->DriverBindingHandle,\r
926 Controller\r
927 );\r
928\r
929 return EFI_SUCCESS;\r
930 }\r
931\r
932 AllChildrenStopped = TRUE;\r
933\r
934 for (Index = 0; Index < NumberOfChildren; Index++) {\r
935\r
936 Status = gBS->OpenProtocol (\r
937 ChildHandleBuffer[Index],\r
938 &gEfiSimpleTextOutProtocolGuid,\r
939 (VOID **) &SimpleTextOutput,\r
940 This->DriverBindingHandle,\r
941 ChildHandleBuffer[Index],\r
942 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
943 );\r
944 if (!EFI_ERROR (Status)) {\r
945\r
946 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);\r
947\r
948 gBS->CloseProtocol (\r
949 Controller,\r
950 &gEfiSerialIoProtocolGuid,\r
951 This->DriverBindingHandle,\r
952 ChildHandleBuffer[Index]\r
953 );\r
954\r
955 Status = gBS->UninstallMultipleProtocolInterfaces (\r
956 ChildHandleBuffer[Index],\r
957 &gEfiSimpleTextInProtocolGuid,\r
958 &TerminalDevice->SimpleInput,\r
66aa04e4 959 &gEfiSimpleTextInputExProtocolGuid,\r
960 &TerminalDevice->SimpleInputEx,\r
95276127 961 &gEfiSimpleTextOutProtocolGuid,\r
962 &TerminalDevice->SimpleTextOutput,\r
963 &gEfiDevicePathProtocolGuid,\r
964 TerminalDevice->DevicePath,\r
965 NULL\r
966 );\r
967 if (EFI_ERROR (Status)) {\r
968 gBS->OpenProtocol (\r
969 Controller,\r
970 &gEfiSerialIoProtocolGuid,\r
971 (VOID **) &SerialIo,\r
972 This->DriverBindingHandle,\r
973 ChildHandleBuffer[Index],\r
974 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
975 );\r
976 } else {\r
977\r
0d8b3f81 978 FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);\r
b7cf1c07 979 StopTerminalStateMachine (TerminalDevice);\r
95276127 980 gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);\r
66aa04e4 981 gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);\r
47b612db 982 gBS->CloseEvent (TerminalDevice->KeyNotifyProcessEvent);\r
66aa04e4 983 TerminalFreeNotifyList (&TerminalDevice->NotifyList);\r
95276127 984 FreePool (TerminalDevice->DevicePath);\r
0d8b3f81 985 FreePool (TerminalDevice->TerminalConsoleModeData);\r
95276127 986 FreePool (TerminalDevice);\r
987 }\r
988 }\r
989\r
990 if (EFI_ERROR (Status)) {\r
991 AllChildrenStopped = FALSE;\r
992 }\r
993 }\r
994\r
995 if (!AllChildrenStopped) {\r
996 return EFI_DEVICE_ERROR;\r
997 }\r
998\r
999 return EFI_SUCCESS;\r
1000}\r
1001\r
b9c04b88
RN
1002/**\r
1003 Compare a device path data structure to that of all the nodes of a\r
1004 second device path instance.\r
1005\r
1006 @param Multi A pointer to a multi-instance device path data structure.\r
1007 @param Single A pointer to a single-instance device path data structure.\r
1008\r
1009 @retval TRUE If the Single is contained within Multi.\r
1010 @retval FALSE The Single is not match within Multi.\r
1011\r
1012**/\r
1013BOOLEAN\r
1014MatchDevicePaths (\r
1015 IN EFI_DEVICE_PATH_PROTOCOL *Multi,\r
1016 IN EFI_DEVICE_PATH_PROTOCOL *Single\r
1017 )\r
1018{\r
1019 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1020 EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;\r
1021 UINTN Size;\r
1022\r
1023 DevicePath = Multi;\r
1024 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);\r
1025 //\r
1026 // Search for the match of 'Single' in 'Multi'\r
1027 //\r
1028 while (DevicePathInst != NULL) {\r
1029 //\r
1030 // If the single device path is found in multiple device paths,\r
1031 // return success\r
1032 //\r
1033 if (CompareMem (Single, DevicePathInst, Size) == 0) {\r
1034 FreePool (DevicePathInst);\r
1035 return TRUE;\r
1036 }\r
1037\r
1038 FreePool (DevicePathInst);\r
1039 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);\r
1040 }\r
1041\r
1042 return FALSE;\r
1043}\r
1044\r
8fd98315 1045/**\r
1046 Update terminal device path in Console Device Environment Variables.\r
1047\r
1048 @param VariableName The Console Device Environment Variable.\r
11baadb6 1049 @param ParentDevicePath The terminal device path to be updated.\r
8fd98315 1050\r
8fd98315 1051**/\r
95276127 1052VOID\r
1053TerminalUpdateConsoleDevVariable (\r
1054 IN CHAR16 *VariableName,\r
1055 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath\r
1056 )\r
1057{\r
1058 EFI_STATUS Status;\r
5070befc 1059 UINTN NameSize;\r
95276127 1060 UINTN VariableSize;\r
8ce87fff 1061 TERMINAL_TYPE TerminalType;\r
95276127 1062 EFI_DEVICE_PATH_PROTOCOL *Variable;\r
1063 EFI_DEVICE_PATH_PROTOCOL *NewVariable;\r
1064 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
5070befc 1065 EDKII_SET_VARIABLE_STATUS *SetVariableStatus;\r
95276127 1066\r
95276127 1067 //\r
1068 // Get global variable and its size according to the name given.\r
1069 //\r
b9c04b88
RN
1070 Status = GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);\r
1071 if (Status == EFI_NOT_FOUND) {\r
1072 Status = EFI_SUCCESS;\r
1073 Variable = NULL;\r
1074 }\r
1075 if (EFI_ERROR (Status)) {\r
e3dcffcc 1076 return;\r
1077 }\r
1078\r
95276127 1079 //\r
1080 // Append terminal device path onto the variable.\r
1081 //\r
f9163275 1082 for (TerminalType = 0; TerminalType < ARRAY_SIZE (mTerminalType); TerminalType++) {\r
95276127 1083 SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);\r
95276127 1084\r
1085 if (TempDevicePath != NULL) {\r
b9c04b88
RN
1086 if (!MatchDevicePaths (Variable, TempDevicePath)) {\r
1087 NewVariable = AppendDevicePathInstance (Variable, TempDevicePath);\r
1088 if (NewVariable != NULL) {\r
1089 if (Variable != NULL) {\r
1090 FreePool (Variable);\r
1091 }\r
1092 Variable = NewVariable;\r
1093 }\r
1094 }\r
1095\r
95276127 1096 FreePool (TempDevicePath);\r
1097 }\r
1098\r
95276127 1099 }\r
1100\r
1101 VariableSize = GetDevicePathSize (Variable);\r
1102\r
1103 Status = gRT->SetVariable (\r
1104 VariableName,\r
1105 &gEfiGlobalVariableGuid,\r
1106 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
1107 VariableSize,\r
1108 Variable\r
1109 );\r
5070befc
RN
1110\r
1111 if (EFI_ERROR (Status)) {\r
1112 NameSize = StrSize (VariableName);\r
1113 SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + VariableSize);\r
1114 if (SetVariableStatus != NULL) {\r
1115 CopyGuid (&SetVariableStatus->Guid, &gEfiGlobalVariableGuid);\r
1116 SetVariableStatus->NameSize = NameSize;\r
1117 SetVariableStatus->DataSize = VariableSize;\r
1118 SetVariableStatus->SetStatus = Status;\r
1119 SetVariableStatus->Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;\r
1120 CopyMem (SetVariableStatus + 1, VariableName, NameSize);\r
1121 CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Variable, VariableSize);\r
1122\r
1123 REPORT_STATUS_CODE_EX (\r
1124 EFI_ERROR_CODE,\r
1125 PcdGet32 (PcdErrorCodeSetVariable),\r
1126 0,\r
1127 NULL,\r
1128 &gEdkiiStatusCodeDataTypeVariableGuid,\r
1129 SetVariableStatus,\r
1130 sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + VariableSize\r
1131 );\r
1132\r
1133 FreePool (SetVariableStatus);\r
1134 }\r
1135 }\r
1136\r
95276127 1137 FreePool (Variable);\r
1138\r
1139 return ;\r
1140}\r
1141\r
e49ef433 1142\r
1143/**\r
8fd98315 1144 Remove terminal device path from Console Device Environment Variables.\r
e49ef433 1145\r
8fd98315 1146 @param VariableName Console Device Environment Variables.\r
11baadb6 1147 @param ParentDevicePath The terminal device path to be updated.\r
e49ef433 1148\r
e49ef433 1149**/\r
95276127 1150VOID\r
1151TerminalRemoveConsoleDevVariable (\r
1152 IN CHAR16 *VariableName,\r
1153 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath\r
1154 )\r
95276127 1155{\r
1156 EFI_STATUS Status;\r
1157 BOOLEAN FoundOne;\r
1158 BOOLEAN Match;\r
1159 UINTN VariableSize;\r
1160 UINTN InstanceSize;\r
8ce87fff 1161 TERMINAL_TYPE TerminalType;\r
95276127 1162 EFI_DEVICE_PATH_PROTOCOL *Instance;\r
1163 EFI_DEVICE_PATH_PROTOCOL *Variable;\r
1164 EFI_DEVICE_PATH_PROTOCOL *OriginalVariable;\r
1165 EFI_DEVICE_PATH_PROTOCOL *NewVariable;\r
1166 EFI_DEVICE_PATH_PROTOCOL *SavedNewVariable;\r
1167 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
1168\r
95276127 1169 Instance = NULL;\r
1170\r
1171 //\r
1172 // Get global variable and its size according to the name given.\r
1173 //\r
f01b91ae 1174 GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);\r
95276127 1175 if (Variable == NULL) {\r
1176 return ;\r
1177 }\r
1178\r
1179 FoundOne = FALSE;\r
1180 OriginalVariable = Variable;\r
1181 NewVariable = NULL;\r
1182\r
1183 //\r
1184 // Get first device path instance from Variable\r
1185 //\r
1186 Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);\r
1187 if (Instance == NULL) {\r
1188 FreePool (OriginalVariable);\r
1189 return ;\r
1190 }\r
1191 //\r
1192 // Loop through all the device path instances of Variable\r
1193 //\r
1194 do {\r
1195 //\r
1196 // Loop through all the terminal types that this driver supports\r
1197 //\r
1198 Match = FALSE;\r
f9163275 1199 for (TerminalType = 0; TerminalType < ARRAY_SIZE (mTerminalType); TerminalType++) {\r
95276127 1200\r
1201 SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);\r
1202\r
1203 //\r
11baadb6 1204 // Compare the generated device path to the current device path instance\r
95276127 1205 //\r
1206 if (TempDevicePath != NULL) {\r
1207 if (CompareMem (Instance, TempDevicePath, InstanceSize) == 0) {\r
1208 Match = TRUE;\r
1209 FoundOne = TRUE;\r
1210 }\r
1211\r
1212 FreePool (TempDevicePath);\r
1213 }\r
1214 }\r
1215 //\r
1216 // If a match was not found, then keep the current device path instance\r
1217 //\r
1218 if (!Match) {\r
1219 SavedNewVariable = NewVariable;\r
1220 NewVariable = AppendDevicePathInstance (NewVariable, Instance);\r
1221 if (SavedNewVariable != NULL) {\r
1222 FreePool (SavedNewVariable);\r
1223 }\r
1224 }\r
1225 //\r
1226 // Get next device path instance from Variable\r
1227 //\r
1228 FreePool (Instance);\r
1229 Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);\r
1230 } while (Instance != NULL);\r
1231\r
1232 FreePool (OriginalVariable);\r
1233\r
1234 if (FoundOne) {\r
1235 VariableSize = GetDevicePathSize (NewVariable);\r
1236\r
1237 Status = gRT->SetVariable (\r
1238 VariableName,\r
1239 &gEfiGlobalVariableGuid,\r
1240 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
1241 VariableSize,\r
1242 NewVariable\r
1243 );\r
5070befc
RN
1244 //\r
1245 // Shrinking variable with existing variable driver implementation shouldn't fail.\r
1246 //\r
1247 ASSERT_EFI_ERROR (Status);\r
95276127 1248 }\r
1249\r
1250 if (NewVariable != NULL) {\r
1251 FreePool (NewVariable);\r
1252 }\r
1253\r
1254 return ;\r
1255}\r
1256\r
8fd98315 1257/**\r
11baadb6 1258 Build terminal device path according to terminal type.\r
8fd98315 1259\r
1260 @param TerminalType The terminal type is PC ANSI, VT100, VT100+ or VT-UTF8.\r
11baadb6 1261 @param ParentDevicePath Parent device path.\r
8fd98315 1262 @param TerminalDevicePath Returned terminal device path, if building successfully.\r
1263\r
1264 @retval EFI_UNSUPPORTED Terminal does not belong to the supported type.\r
1265 @retval EFI_OUT_OF_RESOURCES Generate terminal device path failed.\r
1266 @retval EFI_SUCCESS Build terminal device path successfully.\r
1267\r
1268**/\r
95276127 1269EFI_STATUS\r
1270SetTerminalDevicePath (\r
8ce87fff 1271 IN TERMINAL_TYPE TerminalType,\r
95276127 1272 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
1273 OUT EFI_DEVICE_PATH_PROTOCOL **TerminalDevicePath\r
1274 )\r
1275{\r
1276 VENDOR_DEVICE_PATH Node;\r
1277\r
802c39b0 1278 ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));\r
95276127 1279 Node.Header.Type = MESSAGING_DEVICE_PATH;\r
1280 Node.Header.SubType = MSG_VENDOR_DP;\r
178b6b5d 1281 SetDevicePathNodeLength (&Node.Header, sizeof (VENDOR_DEVICE_PATH));\r
802c39b0 1282 CopyGuid (&Node.Guid, mTerminalType[TerminalType]);\r
ab76200c 1283\r
95276127 1284 //\r
ab76200c 1285 // Append the terminal node onto parent device path\r
95276127 1286 // to generate a complete terminal device path.\r
1287 //\r
1288 *TerminalDevicePath = AppendDevicePathNode (\r
1289 ParentDevicePath,\r
1290 (EFI_DEVICE_PATH_PROTOCOL *) &Node\r
1291 );\r
1292 if (*TerminalDevicePath == NULL) {\r
1293 return EFI_OUT_OF_RESOURCES;\r
1294 }\r
1295\r
1296 return EFI_SUCCESS;\r
1297}\r
1298\r
97a079ed
A
1299/**\r
1300 The user Entry Point for module Terminal. The user code starts with this function.\r
1301\r
ab76200c 1302 @param ImageHandle The firmware allocated handle for the EFI image.\r
1303 @param SystemTable A pointer to the EFI System Table.\r
fb0b259e 1304\r
97a079ed
A
1305 @retval EFI_SUCCESS The entry point is executed successfully.\r
1306 @retval other Some error occurs when executing this entry point.\r
1307\r
1308**/\r
1309EFI_STATUS\r
1310EFIAPI\r
1311InitializeTerminal(\r
1312 IN EFI_HANDLE ImageHandle,\r
1313 IN EFI_SYSTEM_TABLE *SystemTable\r
1314 )\r
1315{\r
1316 EFI_STATUS Status;\r
1317\r
1318 //\r
1319 // Install driver model protocol(s).\r
1320 //\r
5bca971e 1321 Status = EfiLibInstallDriverBindingComponentName2 (\r
97a079ed
A
1322 ImageHandle,\r
1323 SystemTable,\r
1324 &gTerminalDriverBinding,\r
1325 ImageHandle,\r
1326 &gTerminalComponentName,\r
5bca971e 1327 &gTerminalComponentName2\r
97a079ed
A
1328 );\r
1329 ASSERT_EFI_ERROR (Status);\r
1330\r
97a079ed
A
1331 return Status;\r
1332}\r
f1aec6cc 1333\r
1334/**\r
1335 Check if the device supports hot-plug through its device path.\r
1336\r
1337 This function could be updated to check more types of Hot Plug devices.\r
1338 Currently, it checks USB and PCCard device.\r
1339\r
1340 @param DevicePath Pointer to device's device path.\r
1341\r
1342 @retval TRUE The devcie is a hot-plug device\r
1343 @retval FALSE The devcie is not a hot-plug device.\r
1344\r
1345**/\r
1346BOOLEAN\r
1347IsHotPlugDevice (\r
1348 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
1349 )\r
1350{\r
1351 EFI_DEVICE_PATH_PROTOCOL *CheckDevicePath;\r
1352\r
1353 CheckDevicePath = DevicePath;\r
1354 while (!IsDevicePathEnd (CheckDevicePath)) {\r
1355 //\r
1356 // Check device whether is hot plug device or not throught Device Path\r
e3dcffcc 1357 //\r
f1aec6cc 1358 if ((DevicePathType (CheckDevicePath) == MESSAGING_DEVICE_PATH) &&\r
1359 (DevicePathSubType (CheckDevicePath) == MSG_USB_DP ||\r
1360 DevicePathSubType (CheckDevicePath) == MSG_USB_CLASS_DP ||\r
1361 DevicePathSubType (CheckDevicePath) == MSG_USB_WWID_DP)) {\r
1362 //\r
1363 // If Device is USB device\r
1364 //\r
1365 return TRUE;\r
1366 }\r
1367 if ((DevicePathType (CheckDevicePath) == HARDWARE_DEVICE_PATH) &&\r
1368 (DevicePathSubType (CheckDevicePath) == HW_PCCARD_DP)) {\r
1369 //\r
1370 // If Device is PCCard\r
1371 //\r
1372 return TRUE;\r
1373 }\r
e3dcffcc 1374\r
f1aec6cc 1375 CheckDevicePath = NextDevicePathNode (CheckDevicePath);\r
1376 }\r
1377\r
1378 return FALSE;\r
1379}\r
1380\r