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