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