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