A small changing to reduce size for ConSplitter module.
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Universal / Console / ConSplitterDxe / ConSplitter.c
1 /**@file\r
2   Console Splitter Driver. Any Handle that attatched\r
3   EFI_CONSOLE_IDENTIFIER_PROTOCOL can be bound by this driver.\r
4 \r
5   So far it works like any other driver by opening a SimpleTextIn and/or\r
6   SimpleTextOut protocol with EFI_OPEN_PROTOCOL_BY_DRIVER attributes. The big\r
7   difference is this driver does not layer a protocol on the passed in\r
8   handle, or construct a child handle like a standard device or bus driver.\r
9   This driver produces three virtual handles as children, one for console input\r
10   splitter, one for console output splitter and one for error output splitter.\r
11   EFI_CONSOLE_SPLIT_PROTOCOL will be attatched onto each virtual handle to\r
12   identify the splitter type.\r
13 \r
14   Each virtual handle, that supports both the EFI_CONSOLE_SPLIT_PROTOCOL\r
15   and Console I/O protocol, will be produced in the driver entry point.\r
16   The virtual handle are added on driver entry and never removed.\r
17   Such design ensures sytem function well during none console device situation.\r
18 \r
19 Copyright (c) 2006 - 2007 Intel Corporation. <BR>\r
20 All rights reserved. This program and the accompanying materials\r
21 are licensed and made available under the terms and conditions of the BSD License\r
22 which accompanies this distribution.  The full text of the license may be found at\r
23 http://opensource.org/licenses/bsd-license.php\r
24 \r
25 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
26 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
27 \r
28 **/\r
29 \r
30 #include "ConSplitter.h"\r
31 \r
32 //\r
33 // Global Variables\r
34 //\r
35 STATIC TEXT_IN_SPLITTER_PRIVATE_DATA  mConIn = {\r
36   TEXT_IN_SPLITTER_PRIVATE_DATA_SIGNATURE,\r
37   (EFI_HANDLE) NULL,\r
38   {\r
39     ConSplitterTextInReset,\r
40     ConSplitterTextInReadKeyStroke,\r
41     (EFI_EVENT) NULL\r
42   },\r
43   0,\r
44   (EFI_SIMPLE_TEXT_INPUT_PROTOCOL **) NULL,\r
45   0,\r
46   {\r
47     ConSplitterTextInResetEx,\r
48     ConSplitterTextInReadKeyStrokeEx,\r
49     (EFI_EVENT) NULL,\r
50     ConSplitterTextInSetState,\r
51     ConSplitterTextInRegisterKeyNotify,\r
52     ConSplitterTextInUnregisterKeyNotify\r
53   },\r
54   0,\r
55   (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL **) NULL,\r
56   0,\r
57   {\r
58     (struct _LIST_ENTRY     *) NULL,\r
59     (struct _LIST_ENTRY     *) NULL\r
60   },\r
61 \r
62   {\r
63     ConSplitterSimplePointerReset,\r
64     ConSplitterSimplePointerGetState,\r
65     (EFI_EVENT) NULL,\r
66     (EFI_SIMPLE_POINTER_MODE *) NULL\r
67   },\r
68   {\r
69     0x10000,\r
70     0x10000,\r
71     0x10000,\r
72     TRUE,\r
73     TRUE\r
74   },\r
75   0,\r
76   (EFI_SIMPLE_POINTER_PROTOCOL **) NULL,\r
77   0,\r
78 \r
79   {\r
80     ConSplitterAbsolutePointerReset,\r
81     ConSplitterAbsolutePointerGetState,\r
82     (EFI_EVENT) NULL,\r
83     (EFI_ABSOLUTE_POINTER_MODE *) NULL\r
84   },\r
85 \r
86   {\r
87     0,       //AbsoluteMinX\r
88     0,       //AbsoluteMinY\r
89     0,       //AbsoluteMinZ\r
90     0x10000, //AbsoluteMaxX\r
91     0x10000, //AbsoluteMaxY\r
92     0x10000, //AbsoluteMaxZ\r
93     0        //Attributes\r
94   },\r
95   0,\r
96   (EFI_ABSOLUTE_POINTER_PROTOCOL **) NULL,\r
97   0,\r
98   FALSE,\r
99 \r
100   FALSE,\r
101   {\r
102     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
103     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
104     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
105     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\r
106   },\r
107   0,\r
108   {\r
109     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
110     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
111     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
112     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\r
113   },\r
114   (EFI_EVENT) NULL,\r
115 \r
116   FALSE,\r
117   FALSE\r
118 };\r
119 \r
120 GLOBAL_REMOVE_IF_UNREFERENCED EFI_UGA_DRAW_PROTOCOL gUgaDrawProtocolTemplate = {\r
121   ConSpliterUgaDrawGetMode,\r
122   ConSpliterUgaDrawSetMode,\r
123   ConSpliterUgaDrawBlt\r
124 };\r
125 \r
126 GLOBAL_REMOVE_IF_UNREFERENCED EFI_GRAPHICS_OUTPUT_PROTOCOL gGraphicsOutputProtocolTemplate = {\r
127   ConSpliterGraphicsOutputQueryMode,\r
128   ConSpliterGraphicsOutputSetMode,\r
129   ConSpliterGraphicsOutputBlt,\r
130   NULL\r
131 };\r
132 \r
133 STATIC TEXT_OUT_SPLITTER_PRIVATE_DATA mConOut = {\r
134   TEXT_OUT_SPLITTER_PRIVATE_DATA_SIGNATURE,\r
135   (EFI_HANDLE) NULL,\r
136   {\r
137     ConSplitterTextOutReset,\r
138     ConSplitterTextOutOutputString,\r
139     ConSplitterTextOutTestString,\r
140     ConSplitterTextOutQueryMode,\r
141     ConSplitterTextOutSetMode,\r
142     ConSplitterTextOutSetAttribute,\r
143     ConSplitterTextOutClearScreen,\r
144     ConSplitterTextOutSetCursorPosition,\r
145     ConSplitterTextOutEnableCursor,\r
146     (EFI_SIMPLE_TEXT_OUTPUT_MODE *) NULL\r
147   },\r
148   {\r
149     1,\r
150     0,\r
151     0,\r
152     0,\r
153     0,\r
154     FALSE,\r
155   },\r
156   {\r
157     NULL,\r
158     NULL,\r
159     NULL\r
160   },\r
161   0,\r
162   0,\r
163   0,\r
164   0,\r
165   (EFI_UGA_PIXEL *) NULL,\r
166   {\r
167     NULL,\r
168     NULL,\r
169     NULL,\r
170     NULL\r
171   },\r
172   (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) NULL,\r
173   (TEXT_OUT_GOP_MODE *) NULL,\r
174   0,\r
175   TRUE,\r
176   {\r
177     ConSpliterConsoleControlGetMode,\r
178     ConSpliterConsoleControlSetMode,\r
179     ConSpliterConsoleControlLockStdIn\r
180   },\r
181 \r
182   0,\r
183   (TEXT_OUT_AND_GOP_DATA *) NULL,\r
184   0,\r
185   (TEXT_OUT_SPLITTER_QUERY_DATA *) NULL,\r
186   0,\r
187   (INT32 *) NULL,\r
188 \r
189   EfiConsoleControlScreenText,\r
190   0,\r
191   0,\r
192   (CHAR16 *) NULL,\r
193   (INT32 *) NULL\r
194 };\r
195 \r
196 STATIC TEXT_OUT_SPLITTER_PRIVATE_DATA mStdErr = {\r
197   TEXT_OUT_SPLITTER_PRIVATE_DATA_SIGNATURE,\r
198   (EFI_HANDLE) NULL,\r
199   {\r
200     ConSplitterTextOutReset,\r
201     ConSplitterTextOutOutputString,\r
202     ConSplitterTextOutTestString,\r
203     ConSplitterTextOutQueryMode,\r
204     ConSplitterTextOutSetMode,\r
205     ConSplitterTextOutSetAttribute,\r
206     ConSplitterTextOutClearScreen,\r
207     ConSplitterTextOutSetCursorPosition,\r
208     ConSplitterTextOutEnableCursor,\r
209     (EFI_SIMPLE_TEXT_OUTPUT_MODE *) NULL\r
210   },\r
211   {\r
212     1,\r
213     0,\r
214     0,\r
215     0,\r
216     0,\r
217     FALSE,\r
218   },\r
219   {\r
220     NULL,\r
221     NULL,\r
222     NULL\r
223   },\r
224   0,\r
225   0,\r
226   0,\r
227   0,\r
228   (EFI_UGA_PIXEL *) NULL,\r
229   {\r
230     NULL,\r
231     NULL,\r
232     NULL,\r
233     NULL\r
234   },\r
235   (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) NULL,\r
236   (TEXT_OUT_GOP_MODE *) NULL,\r
237   0,\r
238   TRUE,\r
239   {\r
240     ConSpliterConsoleControlGetMode,\r
241     ConSpliterConsoleControlSetMode,\r
242     ConSpliterConsoleControlLockStdIn\r
243   },\r
244 \r
245   0,\r
246   (TEXT_OUT_AND_GOP_DATA *) NULL,\r
247   0,\r
248   (TEXT_OUT_SPLITTER_QUERY_DATA *) NULL,\r
249   0,\r
250   (INT32 *) NULL,\r
251 \r
252   EfiConsoleControlScreenText,\r
253   0,\r
254   0,\r
255   (CHAR16 *) NULL,\r
256   (INT32 *) NULL\r
257 };\r
258 \r
259 EFI_DRIVER_BINDING_PROTOCOL           gConSplitterConInDriverBinding = {\r
260   ConSplitterConInDriverBindingSupported,\r
261   ConSplitterConInDriverBindingStart,\r
262   ConSplitterConInDriverBindingStop,\r
263   0xa,\r
264   NULL,\r
265   NULL\r
266 };\r
267 \r
268 EFI_DRIVER_BINDING_PROTOCOL           gConSplitterSimplePointerDriverBinding = {\r
269   ConSplitterSimplePointerDriverBindingSupported,\r
270   ConSplitterSimplePointerDriverBindingStart,\r
271   ConSplitterSimplePointerDriverBindingStop,\r
272   0xa,\r
273   NULL,\r
274   NULL\r
275 };\r
276 \r
277 //\r
278 // Driver binding instance for Absolute Pointer protocol\r
279 //\r
280 EFI_DRIVER_BINDING_PROTOCOL           gConSplitterAbsolutePointerDriverBinding = {\r
281   ConSplitterAbsolutePointerDriverBindingSupported,\r
282   ConSplitterAbsolutePointerDriverBindingStart,\r
283   ConSplitterAbsolutePointerDriverBindingStop,\r
284   0xa,\r
285   NULL,\r
286   NULL\r
287 };\r
288 \r
289 EFI_DRIVER_BINDING_PROTOCOL           gConSplitterConOutDriverBinding = {\r
290   ConSplitterConOutDriverBindingSupported,\r
291   ConSplitterConOutDriverBindingStart,\r
292   ConSplitterConOutDriverBindingStop,\r
293   0xa,\r
294   NULL,\r
295   NULL\r
296 };\r
297 \r
298 EFI_DRIVER_BINDING_PROTOCOL           gConSplitterStdErrDriverBinding = {\r
299   ConSplitterStdErrDriverBindingSupported,\r
300   ConSplitterStdErrDriverBindingStart,\r
301   ConSplitterStdErrDriverBindingStop,\r
302   0xa,\r
303   NULL,\r
304   NULL\r
305 };\r
306 \r
307 /**\r
308   The user Entry Point for module ConSplitter. The user code starts with this function.\r
309 \r
310   @param[in] ImageHandle    The firmware allocated handle for the EFI image.\r
311   @param[in] SystemTable    A pointer to the EFI System Table.\r
312 \r
313   @retval EFI_SUCCESS       The entry point is executed successfully.\r
314   @retval other             Some error occurs when executing this entry point.\r
315 \r
316 **/\r
317 EFI_STATUS\r
318 EFIAPI\r
319 InitializeConSplitter(\r
320   IN EFI_HANDLE           ImageHandle,\r
321   IN EFI_SYSTEM_TABLE     *SystemTable\r
322   )\r
323 {\r
324   EFI_STATUS              Status;\r
325 \r
326   //\r
327   // Install driver model protocol(s).\r
328   //\r
329   Status = EfiLibInstallDriverBindingComponentName2 (\r
330              ImageHandle,\r
331              SystemTable,\r
332              &gConSplitterConInDriverBinding,\r
333              ImageHandle,\r
334              &gConSplitterConInComponentName,\r
335              &gConSplitterConInComponentName2\r
336              );\r
337   ASSERT_EFI_ERROR (Status);\r
338 \r
339   Status = EfiLibInstallDriverBindingComponentName2 (\r
340              ImageHandle,\r
341              SystemTable,\r
342              &gConSplitterSimplePointerDriverBinding,\r
343              NULL,\r
344              &gConSplitterSimplePointerComponentName,\r
345              &gConSplitterSimplePointerComponentName2\r
346              );\r
347   ASSERT_EFI_ERROR (Status);\r
348 \r
349   Status = EfiLibInstallDriverBindingComponentName2 (\r
350              ImageHandle,\r
351              SystemTable,\r
352              &gConSplitterAbsolutePointerDriverBinding,\r
353              NULL,\r
354              &gConSplitterAbsolutePointerComponentName,\r
355              &gConSplitterAbsolutePointerComponentName2\r
356              );\r
357   ASSERT_EFI_ERROR (Status);\r
358 \r
359   Status = EfiLibInstallDriverBindingComponentName2 (\r
360              ImageHandle,\r
361              SystemTable,\r
362              &gConSplitterConOutDriverBinding,\r
363              NULL,\r
364              &gConSplitterConOutComponentName,\r
365              &gConSplitterConOutComponentName2\r
366              );\r
367   ASSERT_EFI_ERROR (Status);\r
368 \r
369   Status = EfiLibInstallDriverBindingComponentName2 (\r
370              ImageHandle,\r
371              SystemTable,\r
372              &gConSplitterStdErrDriverBinding,\r
373              NULL,\r
374              &gConSplitterStdErrComponentName,\r
375              &gConSplitterStdErrComponentName2\r
376              );\r
377   ASSERT_EFI_ERROR (Status);\r
378 \r
379 \r
380   //\r
381   // Call the original Entry Point\r
382   //\r
383   Status = ConSplitterDriverEntry (ImageHandle, SystemTable);\r
384 \r
385   return Status;\r
386 }\r
387 \r
388 \r
389 EFI_STATUS\r
390 EFIAPI\r
391 ConSplitterDriverEntry (\r
392   IN EFI_HANDLE                       ImageHandle,\r
393   IN EFI_SYSTEM_TABLE                 *SystemTable\r
394   )\r
395 /*++\r
396 \r
397 Routine Description:\r
398   Intialize a virtual console device to act as an agrigator of physical console\r
399   devices.\r
400 \r
401 Arguments:\r
402   ImageHandle - (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT)\r
403   SystemTable - (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT)\r
404 Returns:\r
405   EFI_SUCCESS\r
406 \r
407 --*/\r
408 {\r
409   EFI_STATUS  Status;\r
410 \r
411   ASSERT (FeaturePcdGet (PcdConOutGopSupport) ||\r
412           FeaturePcdGet (PcdConOutUgaSupport));\r
413   //\r
414   // The driver creates virtual handles for ConIn, ConOut, and StdErr.\r
415   // The virtual handles will always exist even if no console exist in the\r
416   // system. This is need to support hotplug devices like USB.\r
417   //\r
418   //\r
419   // Create virtual device handle for StdErr Splitter\r
420   //\r
421   Status = ConSplitterTextOutConstructor (&mStdErr);\r
422   if (!EFI_ERROR (Status)) {\r
423     Status = gBS->InstallMultipleProtocolInterfaces (\r
424                     &mStdErr.VirtualHandle,\r
425                     &gEfiSimpleTextOutProtocolGuid,\r
426                     &mStdErr.TextOut,\r
427                     &gEfiPrimaryStandardErrorDeviceGuid,\r
428                     NULL,\r
429                     NULL\r
430                     );\r
431   }\r
432   //\r
433   // Create virtual device handle for ConIn Splitter\r
434   //\r
435   Status = ConSplitterTextInConstructor (&mConIn);\r
436   if (!EFI_ERROR (Status)) {\r
437     Status = gBS->InstallMultipleProtocolInterfaces (\r
438                     &mConIn.VirtualHandle,\r
439                     &gEfiSimpleTextInProtocolGuid,\r
440                     &mConIn.TextIn,\r
441                     &gEfiSimpleTextInputExProtocolGuid,\r
442                     &mConIn.TextInEx,\r
443                     &gEfiSimplePointerProtocolGuid,\r
444                     &mConIn.SimplePointer,\r
445                     &gEfiAbsolutePointerProtocolGuid,\r
446                     &mConIn.AbsolutePointer,\r
447                     &gEfiPrimaryConsoleInDeviceGuid,\r
448                     NULL,\r
449                     NULL\r
450                     );\r
451     if (!EFI_ERROR (Status)) {\r
452       //\r
453       // Update the EFI System Table with new virtual console\r
454       //\r
455       gST->ConsoleInHandle  = mConIn.VirtualHandle;\r
456       gST->ConIn            = &mConIn.TextIn;\r
457     }\r
458   }\r
459   //\r
460   // Create virtual device handle for ConOut Splitter\r
461   //\r
462   Status = ConSplitterTextOutConstructor (&mConOut);\r
463   if (!EFI_ERROR (Status)) {\r
464     if (!FeaturePcdGet (PcdConOutGopSupport)) {\r
465       //\r
466       // In EFI mode, UGA Draw protocol is installed\r
467       //\r
468       Status = gBS->InstallMultipleProtocolInterfaces (\r
469                       &mConOut.VirtualHandle,\r
470                       &gEfiSimpleTextOutProtocolGuid,\r
471                       &mConOut.TextOut,\r
472                       &gEfiUgaDrawProtocolGuid,\r
473                       &mConOut.UgaDraw,\r
474                       &gEfiConsoleControlProtocolGuid,\r
475                       &mConOut.ConsoleControl,\r
476                       &gEfiPrimaryConsoleOutDeviceGuid,\r
477                       NULL,\r
478                       NULL\r
479                       );\r
480     } else if (!FeaturePcdGet (PcdConOutUgaSupport)) {\r
481       //\r
482       // In UEFI mode, Graphics Output Protocol is installed on virtual handle.\r
483       //\r
484       Status = gBS->InstallMultipleProtocolInterfaces (\r
485                       &mConOut.VirtualHandle,\r
486                       &gEfiSimpleTextOutProtocolGuid,\r
487                       &mConOut.TextOut,\r
488                       &gEfiGraphicsOutputProtocolGuid,\r
489                       &mConOut.GraphicsOutput,\r
490                       &gEfiConsoleControlProtocolGuid,\r
491                       &mConOut.ConsoleControl,\r
492                       &gEfiPrimaryConsoleOutDeviceGuid,\r
493                       NULL,\r
494                       NULL\r
495                       );\r
496     } else {\r
497       //\r
498       // In EFI and UEFI comptible mode, Graphics Output Protocol and UGA are\r
499       // installed on virtual handle.\r
500       //\r
501       Status = gBS->InstallMultipleProtocolInterfaces (\r
502                       &mConOut.VirtualHandle,\r
503                       &gEfiSimpleTextOutProtocolGuid,\r
504                       &mConOut.TextOut,\r
505                       &gEfiGraphicsOutputProtocolGuid,\r
506                       &mConOut.GraphicsOutput,\r
507                       &gEfiUgaDrawProtocolGuid,\r
508                       &mConOut.UgaDraw,\r
509                       &gEfiConsoleControlProtocolGuid,\r
510                       &mConOut.ConsoleControl,\r
511                       &gEfiPrimaryConsoleOutDeviceGuid,\r
512                       NULL,\r
513                       NULL\r
514                       );\r
515     }\r
516 \r
517     if (!EFI_ERROR (Status)) {\r
518       //\r
519       // Update the EFI System Table with new virtual console\r
520       //\r
521       gST->ConsoleOutHandle = mConOut.VirtualHandle;\r
522       gST->ConOut           = &mConOut.TextOut;\r
523     }\r
524 \r
525   }\r
526   //\r
527   // Update the CRC32 in the EFI System Table header\r
528   //\r
529   gST->Hdr.CRC32 = 0;\r
530   gBS->CalculateCrc32 (\r
531         (UINT8 *) &gST->Hdr,\r
532         gST->Hdr.HeaderSize,\r
533         &gST->Hdr.CRC32\r
534         );\r
535 \r
536   return EFI_SUCCESS;\r
537 }\r
538 \r
539 EFI_STATUS\r
540 ConSplitterTextInConstructor (\r
541   TEXT_IN_SPLITTER_PRIVATE_DATA       *ConInPrivate\r
542   )\r
543 /*++\r
544 \r
545 Routine Description:\r
546 \r
547   Construct the ConSplitter.\r
548 \r
549 Arguments:\r
550 \r
551   ConInPrivate    - A pointer to the TEXT_IN_SPLITTER_PRIVATE_DATA structure.\r
552 \r
553 Returns:\r
554   EFI_OUT_OF_RESOURCES - Out of resources.\r
555 \r
556 --*/\r
557 {\r
558   EFI_STATUS  Status;\r
559 \r
560   //\r
561   // Initilize console input splitter's private data.\r
562   //\r
563   Status = ConSplitterGrowBuffer (\r
564             sizeof (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *),\r
565             &ConInPrivate->TextInListCount,\r
566             (VOID **) &ConInPrivate->TextInList\r
567             );\r
568   if (EFI_ERROR (Status)) {\r
569     return EFI_OUT_OF_RESOURCES;\r
570   }\r
571   //\r
572   // Create Event to support locking StdIn Device\r
573   //\r
574   Status = gBS->CreateEvent (\r
575                   EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
576                   TPL_CALLBACK,\r
577                   ConSpliterConsoleControlLockStdInEvent,\r
578                   NULL,\r
579                   &ConInPrivate->LockEvent\r
580                   );\r
581   ASSERT_EFI_ERROR (Status);\r
582 \r
583   Status = gBS->CreateEvent (\r
584                   EVT_NOTIFY_WAIT,\r
585                   TPL_NOTIFY,\r
586                   ConSplitterTextInWaitForKey,\r
587                   ConInPrivate,\r
588                   &ConInPrivate->TextIn.WaitForKey\r
589                   );\r
590   ASSERT_EFI_ERROR (Status);\r
591 \r
592   //\r
593   // Buffer for Simple Text Input Ex Protocol\r
594   //\r
595   Status = ConSplitterGrowBuffer (\r
596              sizeof (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *),\r
597              &ConInPrivate->TextInExListCount,\r
598              (VOID **) &ConInPrivate->TextInExList\r
599              );\r
600   if (EFI_ERROR (Status)) {\r
601     return EFI_OUT_OF_RESOURCES;\r
602   }\r
603 \r
604   Status = gBS->CreateEvent (\r
605                   EVT_NOTIFY_WAIT,\r
606                   TPL_NOTIFY,\r
607                   ConSplitterTextInWaitForKey,\r
608                   ConInPrivate,\r
609                   &ConInPrivate->TextInEx.WaitForKeyEx\r
610                   );\r
611   ASSERT_EFI_ERROR (Status);\r
612 \r
613   InitializeListHead (&ConInPrivate->NotifyList);\r
614 \r
615   //\r
616   // Allocate Buffer and Create Event for Absolute Pointer and Simple Pointer Protocols\r
617   //\r
618   ConInPrivate->AbsolutePointer.Mode = &ConInPrivate->AbsolutePointerMode;\r
619 \r
620   Status = ConSplitterGrowBuffer (\r
621             sizeof (EFI_ABSOLUTE_POINTER_PROTOCOL *),\r
622             &ConInPrivate->AbsolutePointerListCount,\r
623             (VOID **) &ConInPrivate->AbsolutePointerList\r
624             );\r
625   if (EFI_ERROR (Status)) {\r
626     return EFI_OUT_OF_RESOURCES;\r
627   }\r
628 \r
629   Status = gBS->CreateEvent (\r
630             EVT_NOTIFY_WAIT,\r
631             TPL_NOTIFY,\r
632             ConSplitterAbsolutePointerWaitForInput,\r
633             ConInPrivate,\r
634             &ConInPrivate->AbsolutePointer.WaitForInput\r
635         );\r
636   ASSERT_EFI_ERROR (Status);\r
637 \r
638   ConInPrivate->SimplePointer.Mode = &ConInPrivate->SimplePointerMode;\r
639 \r
640   Status = ConSplitterGrowBuffer (\r
641             sizeof (EFI_SIMPLE_POINTER_PROTOCOL *),\r
642             &ConInPrivate->PointerListCount,\r
643             (VOID **) &ConInPrivate->PointerList\r
644             );\r
645   if (EFI_ERROR (Status)) {\r
646     return EFI_OUT_OF_RESOURCES;\r
647   }\r
648 \r
649   Status = gBS->CreateEvent (\r
650                   EVT_NOTIFY_WAIT,\r
651                   TPL_NOTIFY,\r
652                   ConSplitterSimplePointerWaitForInput,\r
653                   ConInPrivate,\r
654                   &ConInPrivate->SimplePointer.WaitForInput\r
655                   );\r
656 \r
657   return Status;\r
658 }\r
659 \r
660 EFI_STATUS\r
661 ConSplitterTextOutConstructor (\r
662   TEXT_OUT_SPLITTER_PRIVATE_DATA      *ConOutPrivate\r
663   )\r
664 {\r
665   EFI_STATUS  Status;\r
666 \r
667   //\r
668   // Copy protocols template\r
669   //\r
670   if (FeaturePcdGet (PcdConOutUgaSupport)) {\r
671     CopyMem (&ConOutPrivate->UgaDraw, &gUgaDrawProtocolTemplate, sizeof (EFI_UGA_DRAW_PROTOCOL));\r
672   }\r
673 \r
674   if (FeaturePcdGet (PcdConOutGopSupport)) {\r
675     CopyMem (&ConOutPrivate->GraphicsOutput, &gGraphicsOutputProtocolTemplate, sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL));\r
676   }\r
677 \r
678   //\r
679   // Initilize console output splitter's private data.\r
680   //\r
681   ConOutPrivate->TextOut.Mode = &ConOutPrivate->TextOutMode;\r
682 \r
683   Status = ConSplitterGrowBuffer (\r
684             sizeof (TEXT_OUT_AND_GOP_DATA),\r
685             &ConOutPrivate->TextOutListCount,\r
686             (VOID **) &ConOutPrivate->TextOutList\r
687             );\r
688   if (EFI_ERROR (Status)) {\r
689     return EFI_OUT_OF_RESOURCES;\r
690   }\r
691 \r
692   Status = ConSplitterGrowBuffer (\r
693             sizeof (TEXT_OUT_SPLITTER_QUERY_DATA),\r
694             &ConOutPrivate->TextOutQueryDataCount,\r
695             (VOID **) &ConOutPrivate->TextOutQueryData\r
696             );\r
697   if (EFI_ERROR (Status)) {\r
698     return EFI_OUT_OF_RESOURCES;\r
699   }\r
700   //\r
701   // Setup the DevNullTextOut console to 80 x 25\r
702   //\r
703   ConOutPrivate->TextOutQueryData[0].Columns  = 80;\r
704   ConOutPrivate->TextOutQueryData[0].Rows     = 25;\r
705   DevNullTextOutSetMode (ConOutPrivate, 0);\r
706 \r
707   if (FeaturePcdGet (PcdConOutUgaSupport)) {\r
708     //\r
709     // Setup the DevNullUgaDraw to 800 x 600 x 32 bits per pixel\r
710     //\r
711     ConSpliterUgaDrawSetMode (&ConOutPrivate->UgaDraw, 800, 600, 32, 60);\r
712   }\r
713   if (FeaturePcdGet (PcdConOutGopSupport)) {\r
714     //\r
715     // Setup resource for mode information in Graphics Output Protocol interface\r
716     //\r
717     if ((ConOutPrivate->GraphicsOutput.Mode = AllocateZeroPool (sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE))) == NULL) {\r
718       return EFI_OUT_OF_RESOURCES;\r
719     }\r
720     if ((ConOutPrivate->GraphicsOutput.Mode->Info = AllocateZeroPool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION))) == NULL) {\r
721       return EFI_OUT_OF_RESOURCES;\r
722     }\r
723     //\r
724     // Setup the DevNullGraphicsOutput to 800 x 600 x 32 bits per pixel\r
725     //\r
726     if ((ConOutPrivate->GraphicsOutputModeBuffer = AllocateZeroPool (sizeof (TEXT_OUT_GOP_MODE))) == NULL) {\r
727       return EFI_OUT_OF_RESOURCES;\r
728     }\r
729     ConOutPrivate->GraphicsOutputModeBuffer[0].HorizontalResolution = 800;\r
730     ConOutPrivate->GraphicsOutputModeBuffer[0].VerticalResolution = 600;\r
731 \r
732     //\r
733     // Initialize the following items, theset items remain unchanged in GraphicsOutput->SetMode()\r
734     //  GraphicsOutputMode->Info->Version, GraphicsOutputMode->Info->PixelFormat\r
735     //  GraphicsOutputMode->SizeOfInfo, GraphicsOutputMode->FrameBufferBase, GraphicsOutputMode->FrameBufferSize\r
736     //\r
737     ConOutPrivate->GraphicsOutput.Mode->Info->Version = 0;\r
738     ConOutPrivate->GraphicsOutput.Mode->Info->PixelFormat = PixelBltOnly;\r
739     ConOutPrivate->GraphicsOutput.Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);\r
740     ConOutPrivate->GraphicsOutput.Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) NULL;\r
741     ConOutPrivate->GraphicsOutput.Mode->FrameBufferSize = 0;\r
742 \r
743     ConOutPrivate->GraphicsOutput.Mode->MaxMode = 1;\r
744     //\r
745     // Initial current mode to unknow state, and then set to mode 0\r
746     //\r
747     ConOutPrivate->GraphicsOutput.Mode->Mode = 0xffff;\r
748     ConOutPrivate->GraphicsOutput.SetMode (&ConOutPrivate->GraphicsOutput, 0);\r
749   }\r
750 \r
751   return Status;\r
752 }\r
753 \r
754 STATIC\r
755 EFI_STATUS\r
756 ConSplitterSupported (\r
757   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
758   IN  EFI_HANDLE                      ControllerHandle,\r
759   IN  EFI_GUID                        *Guid\r
760   )\r
761 /*++\r
762 \r
763 Routine Description:\r
764   Generic Supported Check\r
765 \r
766 Arguments:\r
767   This              - Pointer to protocol.\r
768   ControllerHandle  - Controller Handle.\r
769   Guid              - Guid.\r
770 \r
771 Returns:\r
772 \r
773   EFI_UNSUPPORTED - unsupported.\r
774   EFI_SUCCESS     - operation is OK.\r
775 \r
776 --*/\r
777 {\r
778   EFI_STATUS  Status;\r
779   VOID        *Instance;\r
780 \r
781   //\r
782   // Make sure the Console Splitter does not attempt to attach to itself\r
783   //\r
784   if (ControllerHandle == mConIn.VirtualHandle) {\r
785     return EFI_UNSUPPORTED;\r
786   }\r
787 \r
788   if (ControllerHandle == mConOut.VirtualHandle) {\r
789     return EFI_UNSUPPORTED;\r
790   }\r
791 \r
792   if (ControllerHandle == mStdErr.VirtualHandle) {\r
793     return EFI_UNSUPPORTED;\r
794   }\r
795   //\r
796   // Check to see whether the handle has the ConsoleInDevice GUID on it\r
797   //\r
798   Status = gBS->OpenProtocol (\r
799                   ControllerHandle,\r
800                   Guid,\r
801                   &Instance,\r
802                   This->DriverBindingHandle,\r
803                   ControllerHandle,\r
804                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
805                   );\r
806 \r
807   if (EFI_ERROR (Status)) {\r
808     return Status;\r
809   }\r
810 \r
811   gBS->CloseProtocol (\r
812         ControllerHandle,\r
813         Guid,\r
814         This->DriverBindingHandle,\r
815         ControllerHandle\r
816         );\r
817 \r
818   return EFI_SUCCESS;\r
819 }\r
820 \r
821 EFI_STATUS\r
822 EFIAPI\r
823 ConSplitterConInDriverBindingSupported (\r
824   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
825   IN  EFI_HANDLE                      ControllerHandle,\r
826   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
827   )\r
828 /*++\r
829 \r
830 Routine Description:\r
831   Console In Supported Check\r
832 \r
833 Arguments:\r
834   This              - Pointer to protocol.\r
835   ControllerHandle  - Controller handle.\r
836   RemainingDevicePath  - Remaining device path.\r
837 \r
838 Returns:\r
839 \r
840   EFI_STATUS\r
841 \r
842 --*/\r
843 {\r
844   return ConSplitterSupported (\r
845           This,\r
846           ControllerHandle,\r
847           &gEfiConsoleInDeviceGuid\r
848           );\r
849 }\r
850 \r
851 EFI_STATUS\r
852 EFIAPI\r
853 ConSplitterSimplePointerDriverBindingSupported (\r
854   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
855   IN  EFI_HANDLE                      ControllerHandle,\r
856   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
857   )\r
858 /*++\r
859 \r
860 Routine Description:\r
861   Standard Error Supported Check\r
862 \r
863 Arguments:\r
864   This              - Pointer to protocol.\r
865   ControllerHandle  - Controller handle.\r
866   RemainingDevicePath  - Remaining device path.\r
867 \r
868 Returns:\r
869 \r
870   EFI_STATUS\r
871 \r
872 --*/\r
873 {\r
874   return ConSplitterSupported (\r
875           This,\r
876           ControllerHandle,\r
877           &gEfiSimplePointerProtocolGuid\r
878           );\r
879 }\r
880 \r
881 EFI_STATUS\r
882 EFIAPI\r
883 ConSplitterAbsolutePointerDriverBindingSupported (\r
884   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
885   IN  EFI_HANDLE                      ControllerHandle,\r
886   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
887   )\r
888 /*++\r
889 \r
890 Routine Description:\r
891   Absolute Pointer Supported Check\r
892 \r
893 Arguments:\r
894   This              - Pointer to protocol.\r
895   ControllerHandle  - Controller handle.\r
896   RemainingDevicePath  - Remaining device path.\r
897 \r
898 Returns:\r
899 \r
900   EFI_STATUS\r
901 \r
902 --*/\r
903 {\r
904   return ConSplitterSupported (\r
905           This,\r
906           ControllerHandle,\r
907           &gEfiAbsolutePointerProtocolGuid\r
908           );\r
909 }\r
910 \r
911 EFI_STATUS\r
912 EFIAPI\r
913 ConSplitterConOutDriverBindingSupported (\r
914   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
915   IN  EFI_HANDLE                      ControllerHandle,\r
916   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
917   )\r
918 /*++\r
919 \r
920 Routine Description:\r
921   Console Out Supported Check\r
922 \r
923 Arguments:\r
924   This              - Pointer to protocol.\r
925   ControllerHandle  - Controller handle.\r
926   RemainingDevicePath  - Remaining device path.\r
927 \r
928 Returns:\r
929 \r
930   EFI_STATUS\r
931 \r
932 --*/\r
933 {\r
934   return ConSplitterSupported (\r
935           This,\r
936           ControllerHandle,\r
937           &gEfiConsoleOutDeviceGuid\r
938           );\r
939 }\r
940 \r
941 EFI_STATUS\r
942 EFIAPI\r
943 ConSplitterStdErrDriverBindingSupported (\r
944   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
945   IN  EFI_HANDLE                      ControllerHandle,\r
946   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
947   )\r
948 /*++\r
949 \r
950 Routine Description:\r
951   Standard Error Supported Check\r
952 \r
953 Arguments:\r
954   This              - Pointer to protocol.\r
955   ControllerHandle  - Controller handle.\r
956   RemainingDevicePath  - Remaining device path.\r
957 \r
958 Returns:\r
959 \r
960   EFI_STATUS\r
961 \r
962 --*/\r
963 {\r
964   return ConSplitterSupported (\r
965           This,\r
966           ControllerHandle,\r
967           &gEfiStandardErrorDeviceGuid\r
968           );\r
969 }\r
970 \r
971 STATIC\r
972 EFI_STATUS\r
973 EFIAPI\r
974 ConSplitterStart (\r
975   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
976   IN  EFI_HANDLE                      ControllerHandle,\r
977   IN  EFI_HANDLE                      ConSplitterVirtualHandle,\r
978   IN  EFI_GUID                        *DeviceGuid,\r
979   IN  EFI_GUID                        *InterfaceGuid,\r
980   IN  VOID                            **Interface\r
981   )\r
982 /*++\r
983 \r
984 Routine Description:\r
985   Start ConSplitter on ControllerHandle, and create the virtual\r
986   agrogated console device on first call Start for a SimpleTextIn handle.\r
987 \r
988 Arguments:\r
989   (Standard DriverBinding Protocol Start() function)\r
990 \r
991 Returns:\r
992   EFI_ERROR if a SimpleTextIn protocol is not started.\r
993 \r
994 --*/\r
995 {\r
996   EFI_STATUS  Status;\r
997   VOID        *Instance;\r
998 \r
999   //\r
1000   // Check to see whether the handle has the ConsoleInDevice GUID on it\r
1001   //\r
1002   Status = gBS->OpenProtocol (\r
1003                   ControllerHandle,\r
1004                   DeviceGuid,\r
1005                   &Instance,\r
1006                   This->DriverBindingHandle,\r
1007                   ControllerHandle,\r
1008                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
1009                   );\r
1010   if (EFI_ERROR (Status)) {\r
1011     return Status;\r
1012   }\r
1013 \r
1014   Status = gBS->OpenProtocol (\r
1015                   ControllerHandle,\r
1016                   DeviceGuid,\r
1017                   &Instance,\r
1018                   This->DriverBindingHandle,\r
1019                   ConSplitterVirtualHandle,\r
1020                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
1021                   );\r
1022   if (EFI_ERROR (Status)) {\r
1023     return Status;\r
1024   }\r
1025 \r
1026   return gBS->OpenProtocol (\r
1027                 ControllerHandle,\r
1028                 InterfaceGuid,\r
1029                 Interface,\r
1030                 This->DriverBindingHandle,\r
1031                 ConSplitterVirtualHandle,\r
1032                 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1033                 );\r
1034 }\r
1035 \r
1036 EFI_STATUS\r
1037 EFIAPI\r
1038 ConSplitterConInDriverBindingStart (\r
1039   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
1040   IN  EFI_HANDLE                      ControllerHandle,\r
1041   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
1042   )\r
1043 /*++\r
1044 \r
1045 Routine Description:\r
1046   Start ConSplitter on ControllerHandle, and create the virtual\r
1047   agrogated console device on first call Start for a SimpleTextIn handle.\r
1048 \r
1049 Arguments:\r
1050   This              - Pointer to protocol.\r
1051   ControllerHandle  - Controller handle.\r
1052   RemainingDevicePath  - Remaining device path.\r
1053 \r
1054 Returns:\r
1055 \r
1056   EFI_STATUS\r
1057   EFI_ERROR if a SimpleTextIn protocol is not started.\r
1058 \r
1059 --*/\r
1060 {\r
1061   EFI_STATUS                     Status;\r
1062   EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn;\r
1063   EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx;\r
1064 \r
1065   //\r
1066   // Start ConSplitter on ControllerHandle, and create the virtual\r
1067   // agrogated console device on first call Start for a SimpleTextIn handle.\r
1068   //\r
1069   Status = ConSplitterStart (\r
1070             This,\r
1071             ControllerHandle,\r
1072             mConIn.VirtualHandle,\r
1073             &gEfiConsoleInDeviceGuid,\r
1074             &gEfiSimpleTextInProtocolGuid,\r
1075             (VOID **) &TextIn\r
1076             );\r
1077   if (EFI_ERROR (Status)) {\r
1078     return Status;\r
1079   }\r
1080 \r
1081   Status = ConSplitterTextInAddDevice (&mConIn, TextIn);\r
1082   if (EFI_ERROR (Status)) {\r
1083     return Status;\r
1084   }\r
1085 \r
1086   Status = gBS->OpenProtocol (\r
1087                   ControllerHandle,\r
1088                   &gEfiSimpleTextInputExProtocolGuid,\r
1089                   (VOID **) &TextInEx,\r
1090                   This->DriverBindingHandle,\r
1091                   mConIn.VirtualHandle,\r
1092                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1093                   );\r
1094   if (EFI_ERROR (Status)) {\r
1095     return Status;\r
1096   }\r
1097 \r
1098   Status = ConSplitterTextInExAddDevice (&mConIn, TextInEx);\r
1099 \r
1100   return Status;\r
1101 }\r
1102 \r
1103 EFI_STATUS\r
1104 EFIAPI\r
1105 ConSplitterSimplePointerDriverBindingStart (\r
1106   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
1107   IN  EFI_HANDLE                      ControllerHandle,\r
1108   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
1109   )\r
1110 /*++\r
1111 \r
1112 Routine Description:\r
1113   Start ConSplitter on ControllerHandle, and create the virtual\r
1114   agrogated console device on first call Start for a SimpleTextIn handle.\r
1115 \r
1116 Arguments:\r
1117   This              - Pointer to protocol.\r
1118   ControllerHandle  - Controller handle.\r
1119   RemainingDevicePath  - Remaining device path.\r
1120 \r
1121 Returns:\r
1122 \r
1123   EFI_ERROR if a SimpleTextIn protocol is not started.\r
1124 \r
1125 --*/\r
1126 {\r
1127   EFI_STATUS                  Status;\r
1128   EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer;\r
1129 \r
1130   Status = ConSplitterStart (\r
1131             This,\r
1132             ControllerHandle,\r
1133             mConIn.VirtualHandle,\r
1134             &gEfiSimplePointerProtocolGuid,\r
1135             &gEfiSimplePointerProtocolGuid,\r
1136             (VOID **) &SimplePointer\r
1137             );\r
1138   if (EFI_ERROR (Status)) {\r
1139     return Status;\r
1140   }\r
1141 \r
1142   return ConSplitterSimplePointerAddDevice (&mConIn, SimplePointer);\r
1143 }\r
1144 \r
1145 EFI_STATUS\r
1146 EFIAPI\r
1147 ConSplitterAbsolutePointerDriverBindingStart (\r
1148   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
1149   IN  EFI_HANDLE                      ControllerHandle,\r
1150   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
1151   )\r
1152 /*++\r
1153 \r
1154 Routine Description:\r
1155   Start ConSplitter on ControllerHandle, and create the virtual\r
1156   agrogated console device on first call Start for a ConIn handle.\r
1157 \r
1158 Arguments:\r
1159   This                 - Pointer to protocol.\r
1160   ControllerHandle     - Controller handle.\r
1161   RemainingDevicePath  - Remaining device path.\r
1162 \r
1163 Returns:\r
1164 \r
1165   EFI_ERROR if a AbsolutePointer protocol is not started.\r
1166 \r
1167 --*/\r
1168 {\r
1169   EFI_STATUS                        Status;\r
1170   EFI_ABSOLUTE_POINTER_PROTOCOL     *AbsolutePointer;\r
1171 \r
1172   Status = ConSplitterStart (\r
1173              This,\r
1174              ControllerHandle,\r
1175              mConIn.VirtualHandle,\r
1176              &gEfiAbsolutePointerProtocolGuid,\r
1177              &gEfiAbsolutePointerProtocolGuid,\r
1178              (VOID **) &AbsolutePointer\r
1179              );\r
1180 \r
1181   if (EFI_ERROR (Status)) {\r
1182     return Status;\r
1183   }\r
1184 \r
1185   return ConSplitterAbsolutePointerAddDevice (&mConIn, AbsolutePointer);\r
1186 }\r
1187 \r
1188 EFI_STATUS\r
1189 EFIAPI\r
1190 ConSplitterConOutDriverBindingStart (\r
1191   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
1192   IN  EFI_HANDLE                      ControllerHandle,\r
1193   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
1194   )\r
1195 /*++\r
1196 \r
1197 Routine Description:\r
1198   Start ConSplitter on ControllerHandle, and create the virtual\r
1199   agrogated console device on first call Start for a SimpleTextIn handle.\r
1200 \r
1201 Arguments:\r
1202   This              - Pointer to protocol.\r
1203   ControllerHandle  - Controller handle.\r
1204   RemainingDevicePath  - Remaining device path.\r
1205 \r
1206 Returns:\r
1207   EFI_ERROR if a SimpleTextIn protocol is not started.\r
1208 \r
1209 --*/\r
1210 {\r
1211   EFI_STATUS                       Status;\r
1212   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *TextOut;\r
1213   EFI_GRAPHICS_OUTPUT_PROTOCOL     *GraphicsOutput;\r
1214   EFI_UGA_DRAW_PROTOCOL            *UgaDraw;\r
1215 \r
1216   Status = ConSplitterStart (\r
1217             This,\r
1218             ControllerHandle,\r
1219             mConOut.VirtualHandle,\r
1220             &gEfiConsoleOutDeviceGuid,\r
1221             &gEfiSimpleTextOutProtocolGuid,\r
1222             (VOID **) &TextOut\r
1223             );\r
1224   if (EFI_ERROR (Status)) {\r
1225     return Status;\r
1226   }\r
1227   //\r
1228   // Try to Open Graphics Output protocol\r
1229   //\r
1230   Status = gBS->OpenProtocol (\r
1231                   ControllerHandle,\r
1232                   &gEfiGraphicsOutputProtocolGuid,\r
1233                   (VOID **) &GraphicsOutput,\r
1234                   This->DriverBindingHandle,\r
1235                   mConOut.VirtualHandle,\r
1236                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1237                   );\r
1238   if (EFI_ERROR (Status)) {\r
1239     GraphicsOutput = NULL;\r
1240   }\r
1241   //\r
1242   // Open UGA_DRAW protocol\r
1243   //\r
1244   Status = gBS->OpenProtocol (\r
1245                   ControllerHandle,\r
1246                   &gEfiUgaDrawProtocolGuid,\r
1247                   (VOID **) &UgaDraw,\r
1248                   This->DriverBindingHandle,\r
1249                   mConOut.VirtualHandle,\r
1250                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1251                   );\r
1252   if (EFI_ERROR (Status)) {\r
1253     UgaDraw = NULL;\r
1254   }\r
1255   //\r
1256   // If both ConOut and StdErr incorporate the same Text Out device,\r
1257   // their MaxMode and QueryData should be the intersection of both.\r
1258   //\r
1259   Status = ConSplitterTextOutAddDevice (&mConOut, TextOut, GraphicsOutput, UgaDraw);\r
1260   ConSplitterTextOutSetAttribute (&mConOut.TextOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
1261 \r
1262   if (FeaturePcdGet (PcdConOutUgaSupport)) {\r
1263     //\r
1264     // Match the UGA mode data of ConOut with the current mode\r
1265     //\r
1266     if (UgaDraw != NULL) {\r
1267       UgaDraw->GetMode (\r
1268                  UgaDraw,\r
1269                  &mConOut.UgaHorizontalResolution,\r
1270                  &mConOut.UgaVerticalResolution,\r
1271                  &mConOut.UgaColorDepth,\r
1272                  &mConOut.UgaRefreshRate\r
1273                  );\r
1274     }\r
1275   }\r
1276   return Status;\r
1277 }\r
1278 \r
1279 EFI_STATUS\r
1280 EFIAPI\r
1281 ConSplitterStdErrDriverBindingStart (\r
1282   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
1283   IN  EFI_HANDLE                      ControllerHandle,\r
1284   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
1285   )\r
1286 /*++\r
1287 \r
1288 Routine Description:\r
1289   Start ConSplitter on ControllerHandle, and create the virtual\r
1290   agrogated console device on first call Start for a SimpleTextIn handle.\r
1291 \r
1292 Arguments:\r
1293   This              - Pointer to protocol.\r
1294   ControllerHandle  - Controller handle.\r
1295   RemainingDevicePath  - Remaining device path.\r
1296 \r
1297 Returns:\r
1298   EFI_ERROR if a SimpleTextIn protocol is not started.\r
1299 \r
1300 --*/\r
1301 {\r
1302   EFI_STATUS                       Status;\r
1303   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *TextOut;\r
1304 \r
1305   Status = ConSplitterStart (\r
1306             This,\r
1307             ControllerHandle,\r
1308             mStdErr.VirtualHandle,\r
1309             &gEfiStandardErrorDeviceGuid,\r
1310             &gEfiSimpleTextOutProtocolGuid,\r
1311             (VOID **) &TextOut\r
1312             );\r
1313   if (EFI_ERROR (Status)) {\r
1314     return Status;\r
1315   }\r
1316   //\r
1317   // If both ConOut and StdErr incorporate the same Text Out device,\r
1318   // their MaxMode and QueryData should be the intersection of both.\r
1319   //\r
1320   Status = ConSplitterTextOutAddDevice (&mStdErr, TextOut, NULL, NULL);\r
1321   ConSplitterTextOutSetAttribute (&mStdErr.TextOut, EFI_TEXT_ATTR (EFI_MAGENTA, EFI_BLACK));\r
1322   if (EFI_ERROR (Status)) {\r
1323     return Status;\r
1324   }\r
1325 \r
1326   if (mStdErr.CurrentNumberOfConsoles == 1) {\r
1327     gST->StandardErrorHandle  = mStdErr.VirtualHandle;\r
1328     gST->StdErr               = &mStdErr.TextOut;\r
1329     //\r
1330     // Update the CRC32 in the EFI System Table header\r
1331     //\r
1332     gST->Hdr.CRC32 = 0;\r
1333     gBS->CalculateCrc32 (\r
1334           (UINT8 *) &gST->Hdr,\r
1335           gST->Hdr.HeaderSize,\r
1336           &gST->Hdr.CRC32\r
1337           );\r
1338   }\r
1339 \r
1340   return Status;\r
1341 }\r
1342 \r
1343 STATIC\r
1344 EFI_STATUS\r
1345 EFIAPI\r
1346 ConSplitterStop (\r
1347   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
1348   IN  EFI_HANDLE                      ControllerHandle,\r
1349   IN  EFI_HANDLE                      ConSplitterVirtualHandle,\r
1350   IN  EFI_GUID                        *DeviceGuid,\r
1351   IN  EFI_GUID                        *InterfaceGuid,\r
1352   IN  VOID                            **Interface\r
1353   )\r
1354 /*++\r
1355 \r
1356 Routine Description:\r
1357 \r
1358 Arguments:\r
1359   (Standard DriverBinding Protocol Stop() function)\r
1360 \r
1361 Returns:\r
1362 \r
1363   None\r
1364 \r
1365 --*/\r
1366 {\r
1367   EFI_STATUS  Status;\r
1368 \r
1369   Status = gBS->OpenProtocol (\r
1370                   ControllerHandle,\r
1371                   InterfaceGuid,\r
1372                   Interface,\r
1373                   This->DriverBindingHandle,\r
1374                   ControllerHandle,\r
1375                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1376                   );\r
1377   if (EFI_ERROR (Status)) {\r
1378     return Status;\r
1379   }\r
1380   //\r
1381   // close the protocol refered.\r
1382   //\r
1383   gBS->CloseProtocol (\r
1384         ControllerHandle,\r
1385         DeviceGuid,\r
1386         This->DriverBindingHandle,\r
1387         ConSplitterVirtualHandle\r
1388         );\r
1389   gBS->CloseProtocol (\r
1390         ControllerHandle,\r
1391         DeviceGuid,\r
1392         This->DriverBindingHandle,\r
1393         ControllerHandle\r
1394         );\r
1395 \r
1396   return EFI_SUCCESS;\r
1397 }\r
1398 \r
1399 EFI_STATUS\r
1400 EFIAPI\r
1401 ConSplitterConInDriverBindingStop (\r
1402   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
1403   IN  EFI_HANDLE                      ControllerHandle,\r
1404   IN  UINTN                           NumberOfChildren,\r
1405   IN  EFI_HANDLE                      *ChildHandleBuffer\r
1406   )\r
1407 /*++\r
1408 \r
1409 Routine Description:\r
1410 \r
1411 Arguments:\r
1412   (Standard DriverBinding Protocol Stop() function)\r
1413 \r
1414 Returns:\r
1415 \r
1416   None\r
1417 \r
1418 --*/\r
1419 {\r
1420   EFI_STATUS                     Status;\r
1421   EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn;\r
1422 \r
1423   EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx;\r
1424   if (NumberOfChildren == 0) {\r
1425     return EFI_SUCCESS;\r
1426   }\r
1427 \r
1428   Status = gBS->OpenProtocol (\r
1429                   ControllerHandle,\r
1430                   &gEfiSimpleTextInputExProtocolGuid,\r
1431                   (VOID **) &TextInEx,\r
1432                   This->DriverBindingHandle,\r
1433                   ControllerHandle,\r
1434                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1435                   );\r
1436   if (EFI_ERROR (Status)) {\r
1437     return Status;\r
1438   }\r
1439 \r
1440   Status = ConSplitterTextInExDeleteDevice (&mConIn, TextInEx);\r
1441   if (EFI_ERROR (Status)) {\r
1442     return Status;\r
1443   }\r
1444 \r
1445 \r
1446   Status = ConSplitterStop (\r
1447             This,\r
1448             ControllerHandle,\r
1449             mConIn.VirtualHandle,\r
1450             &gEfiConsoleInDeviceGuid,\r
1451             &gEfiSimpleTextInProtocolGuid,\r
1452             (VOID **) &TextIn\r
1453             );\r
1454   if (EFI_ERROR (Status)) {\r
1455     return Status;\r
1456   }\r
1457   //\r
1458   // Delete this console input device's data structures.\r
1459   //\r
1460   return ConSplitterTextInDeleteDevice (&mConIn, TextIn);\r
1461 }\r
1462 \r
1463 EFI_STATUS\r
1464 EFIAPI\r
1465 ConSplitterSimplePointerDriverBindingStop (\r
1466   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
1467   IN  EFI_HANDLE                      ControllerHandle,\r
1468   IN  UINTN                           NumberOfChildren,\r
1469   IN  EFI_HANDLE                      *ChildHandleBuffer\r
1470   )\r
1471 /*++\r
1472 \r
1473 Routine Description:\r
1474 \r
1475 Arguments:\r
1476   (Standard DriverBinding Protocol Stop() function)\r
1477 \r
1478 Returns:\r
1479 \r
1480   None\r
1481 \r
1482 --*/\r
1483 {\r
1484   EFI_STATUS                  Status;\r
1485   EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer;\r
1486 \r
1487   if (NumberOfChildren == 0) {\r
1488     return EFI_SUCCESS;\r
1489   }\r
1490 \r
1491   Status = ConSplitterStop (\r
1492             This,\r
1493             ControllerHandle,\r
1494             mConIn.VirtualHandle,\r
1495             &gEfiSimplePointerProtocolGuid,\r
1496             &gEfiSimplePointerProtocolGuid,\r
1497             (VOID **) &SimplePointer\r
1498             );\r
1499   if (EFI_ERROR (Status)) {\r
1500     return Status;\r
1501   }\r
1502   //\r
1503   // Delete this console input device's data structures.\r
1504   //\r
1505   return ConSplitterSimplePointerDeleteDevice (&mConIn, SimplePointer);\r
1506 }\r
1507 \r
1508 EFI_STATUS\r
1509 EFIAPI\r
1510 ConSplitterAbsolutePointerDriverBindingStop (\r
1511   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
1512   IN  EFI_HANDLE                      ControllerHandle,\r
1513   IN  UINTN                           NumberOfChildren,\r
1514   IN  EFI_HANDLE                      *ChildHandleBuffer\r
1515   )\r
1516 /*++\r
1517 \r
1518 Routine Description:\r
1519 \r
1520 Arguments:\r
1521   (Standard DriverBinding Protocol Stop() function)\r
1522 \r
1523 Returns:\r
1524 \r
1525   None\r
1526 \r
1527 --*/\r
1528 {\r
1529   EFI_STATUS                        Status;\r
1530   EFI_ABSOLUTE_POINTER_PROTOCOL     *AbsolutePointer;\r
1531 \r
1532   if (NumberOfChildren == 0) {\r
1533     return EFI_SUCCESS;\r
1534   }\r
1535 \r
1536   Status = ConSplitterStop (\r
1537              This,\r
1538              ControllerHandle,\r
1539              mConIn.VirtualHandle,\r
1540              &gEfiAbsolutePointerProtocolGuid,\r
1541              &gEfiAbsolutePointerProtocolGuid,\r
1542              (VOID **) &AbsolutePointer\r
1543              );\r
1544   if (EFI_ERROR (Status)) {\r
1545     return Status;\r
1546   }\r
1547   //\r
1548   // Delete this console input device's data structures.\r
1549   //\r
1550   return ConSplitterAbsolutePointerDeleteDevice (&mConIn, AbsolutePointer);\r
1551 }\r
1552 \r
1553 EFI_STATUS\r
1554 EFIAPI\r
1555 ConSplitterConOutDriverBindingStop (\r
1556   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
1557   IN  EFI_HANDLE                      ControllerHandle,\r
1558   IN  UINTN                           NumberOfChildren,\r
1559   IN  EFI_HANDLE                      *ChildHandleBuffer\r
1560   )\r
1561 /*++\r
1562 \r
1563 Routine Description:\r
1564 \r
1565 Arguments:\r
1566   (Standard DriverBinding Protocol Stop() function)\r
1567 \r
1568 Returns:\r
1569 \r
1570   None\r
1571 \r
1572 --*/\r
1573 {\r
1574   EFI_STATUS                       Status;\r
1575   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *TextOut;\r
1576 \r
1577   if (NumberOfChildren == 0) {\r
1578     return EFI_SUCCESS;\r
1579   }\r
1580 \r
1581   Status = ConSplitterStop (\r
1582             This,\r
1583             ControllerHandle,\r
1584             mConOut.VirtualHandle,\r
1585             &gEfiConsoleOutDeviceGuid,\r
1586             &gEfiSimpleTextOutProtocolGuid,\r
1587             (VOID **) &TextOut\r
1588             );\r
1589   if (EFI_ERROR (Status)) {\r
1590     return Status;\r
1591   }\r
1592 \r
1593   //\r
1594   // Delete this console output device's data structures.\r
1595   //\r
1596   return ConSplitterTextOutDeleteDevice (&mConOut, TextOut);\r
1597 }\r
1598 \r
1599 EFI_STATUS\r
1600 EFIAPI\r
1601 ConSplitterStdErrDriverBindingStop (\r
1602   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
1603   IN  EFI_HANDLE                      ControllerHandle,\r
1604   IN  UINTN                           NumberOfChildren,\r
1605   IN  EFI_HANDLE                      *ChildHandleBuffer\r
1606   )\r
1607 /*++\r
1608 \r
1609 Routine Description:\r
1610 \r
1611 Arguments:\r
1612   (Standard DriverBinding Protocol Stop() function)\r
1613 \r
1614 Returns:\r
1615 \r
1616   EFI_SUCCESS - Complete successfully.\r
1617 \r
1618 --*/\r
1619 {\r
1620   EFI_STATUS                       Status;\r
1621   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *TextOut;\r
1622 \r
1623   if (NumberOfChildren == 0) {\r
1624     return EFI_SUCCESS;\r
1625   }\r
1626 \r
1627   Status = ConSplitterStop (\r
1628             This,\r
1629             ControllerHandle,\r
1630             mStdErr.VirtualHandle,\r
1631             &gEfiStandardErrorDeviceGuid,\r
1632             &gEfiSimpleTextOutProtocolGuid,\r
1633             (VOID **) &TextOut\r
1634             );\r
1635   if (EFI_ERROR (Status)) {\r
1636     return Status;\r
1637   }\r
1638   //\r
1639   // Delete this console error out device's data structures.\r
1640   //\r
1641   Status = ConSplitterTextOutDeleteDevice (&mStdErr, TextOut);\r
1642   if (EFI_ERROR (Status)) {\r
1643     return Status;\r
1644   }\r
1645 \r
1646   if (mStdErr.CurrentNumberOfConsoles == 0) {\r
1647     gST->StandardErrorHandle  = NULL;\r
1648     gST->StdErr               = NULL;\r
1649     //\r
1650     // Update the CRC32 in the EFI System Table header\r
1651     //\r
1652     gST->Hdr.CRC32 = 0;\r
1653     gBS->CalculateCrc32 (\r
1654           (UINT8 *) &gST->Hdr,\r
1655           gST->Hdr.HeaderSize,\r
1656           &gST->Hdr.CRC32\r
1657           );\r
1658   }\r
1659 \r
1660   return Status;\r
1661 }\r
1662 \r
1663 EFI_STATUS\r
1664 ConSplitterGrowBuffer (\r
1665   IN  UINTN                           SizeOfCount,\r
1666   IN  UINTN                           *Count,\r
1667   IN OUT  VOID                        **Buffer\r
1668   )\r
1669 /*++\r
1670 \r
1671 Routine Description:\r
1672   Take the passed in Buffer of size SizeOfCount and grow the buffer\r
1673   by MAX (CONSOLE_SPLITTER_CONSOLES_ALLOC_UNIT, MaxGrow) * SizeOfCount\r
1674   bytes. Copy the current data in Buffer to the new version of Buffer\r
1675   and free the old version of buffer.\r
1676 \r
1677 \r
1678 Arguments:\r
1679   SizeOfCount - Size of element in array\r
1680   Count       - Current number of elements in array\r
1681   Buffer      - Bigger version of passed in Buffer with all the data\r
1682 \r
1683 Returns:\r
1684   EFI_SUCCESS - Buffer size has grown\r
1685   EFI_OUT_OF_RESOURCES - Could not grow the buffer size\r
1686 \r
1687   None\r
1688 \r
1689 --*/\r
1690 {\r
1691   UINTN NewSize;\r
1692   UINTN OldSize;\r
1693   VOID  *Ptr;\r
1694 \r
1695   //\r
1696   // grow the buffer to new buffer size,\r
1697   // copy the old buffer's content to the new-size buffer,\r
1698   // then free the old buffer.\r
1699   //\r
1700   OldSize = *Count * SizeOfCount;\r
1701   *Count += CONSOLE_SPLITTER_CONSOLES_ALLOC_UNIT;\r
1702   NewSize = *Count * SizeOfCount;\r
1703 \r
1704   Ptr     = AllocateZeroPool (NewSize);\r
1705   if (Ptr == NULL) {\r
1706     return EFI_OUT_OF_RESOURCES;\r
1707   }\r
1708 \r
1709   CopyMem (Ptr, *Buffer, OldSize);\r
1710 \r
1711   if (*Buffer != NULL) {\r
1712     FreePool (*Buffer);\r
1713   }\r
1714 \r
1715   *Buffer = Ptr;\r
1716 \r
1717   return EFI_SUCCESS;\r
1718 }\r
1719 \r
1720 EFI_STATUS\r
1721 ConSplitterTextInAddDevice (\r
1722   IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,\r
1723   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *TextIn\r
1724   )\r
1725 /*++\r
1726 \r
1727 Routine Description:\r
1728 \r
1729 Arguments:\r
1730 \r
1731 Returns:\r
1732 \r
1733   EFI_SUCCESS\r
1734   EFI_OUT_OF_RESOURCES\r
1735 \r
1736 --*/\r
1737 {\r
1738   EFI_STATUS  Status;\r
1739 \r
1740   //\r
1741   // If the Text In List is full, enlarge it by calling growbuffer().\r
1742   //\r
1743   if (Private->CurrentNumberOfConsoles >= Private->TextInListCount) {\r
1744     Status = ConSplitterGrowBuffer (\r
1745               sizeof (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *),\r
1746               &Private->TextInListCount,\r
1747               (VOID **) &Private->TextInList\r
1748               );\r
1749     if (EFI_ERROR (Status)) {\r
1750       return EFI_OUT_OF_RESOURCES;\r
1751     }\r
1752   }\r
1753   //\r
1754   // Add the new text-in device data structure into the Text In List.\r
1755   //\r
1756   Private->TextInList[Private->CurrentNumberOfConsoles] = TextIn;\r
1757   Private->CurrentNumberOfConsoles++;\r
1758 \r
1759   //\r
1760   // Extra CheckEvent added to reduce the double CheckEvent() in UI.c\r
1761   //\r
1762   gBS->CheckEvent (TextIn->WaitForKey);\r
1763 \r
1764   return EFI_SUCCESS;\r
1765 }\r
1766 \r
1767 EFI_STATUS\r
1768 ConSplitterTextInDeleteDevice (\r
1769   IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,\r
1770   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *TextIn\r
1771   )\r
1772 /*++\r
1773 \r
1774 Routine Description:\r
1775 \r
1776 Arguments:\r
1777 \r
1778 Returns:\r
1779 \r
1780   EFI_SUCCESS\r
1781   EFI_NOT_FOUND\r
1782 \r
1783 --*/\r
1784 {\r
1785   UINTN Index;\r
1786   //\r
1787   // Remove the specified text-in device data structure from the Text In List,\r
1788   // and rearrange the remaining data structures in the Text In List.\r
1789   //\r
1790   for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {\r
1791     if (Private->TextInList[Index] == TextIn) {\r
1792       for (Index = Index; Index < Private->CurrentNumberOfConsoles - 1; Index++) {\r
1793         Private->TextInList[Index] = Private->TextInList[Index + 1];\r
1794       }\r
1795 \r
1796       Private->CurrentNumberOfConsoles--;\r
1797       return EFI_SUCCESS;\r
1798     }\r
1799   }\r
1800 \r
1801   return EFI_NOT_FOUND;\r
1802 }\r
1803 \r
1804 EFI_STATUS\r
1805 ConSplitterTextInExAddDevice (\r
1806   IN  TEXT_IN_SPLITTER_PRIVATE_DATA         *Private,\r
1807   IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL     *TextInEx\r
1808   )\r
1809 {\r
1810   EFI_STATUS  Status;\r
1811 \r
1812   //\r
1813   // If the TextInEx List is full, enlarge it by calling growbuffer().\r
1814   //\r
1815   if (Private->CurrentNumberOfExConsoles >= Private->TextInExListCount) {\r
1816     Status = ConSplitterGrowBuffer (\r
1817               sizeof (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *),\r
1818               &Private->TextInExListCount,\r
1819               (VOID **) &Private->TextInExList\r
1820               );\r
1821     if (EFI_ERROR (Status)) {\r
1822       return EFI_OUT_OF_RESOURCES;\r
1823     }\r
1824   }\r
1825   //\r
1826   // Add the new text-in device data structure into the Text In List.\r
1827   //\r
1828   Private->TextInExList[Private->CurrentNumberOfExConsoles] = TextInEx;\r
1829   Private->CurrentNumberOfExConsoles++;\r
1830 \r
1831   //\r
1832   // Extra CheckEvent added to reduce the double CheckEvent() in UI.c\r
1833   //\r
1834   gBS->CheckEvent (TextInEx->WaitForKeyEx);\r
1835 \r
1836   return EFI_SUCCESS;\r
1837 }\r
1838 \r
1839 EFI_STATUS\r
1840 ConSplitterTextInExDeleteDevice (\r
1841   IN  TEXT_IN_SPLITTER_PRIVATE_DATA         *Private,\r
1842   IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL     *TextInEx\r
1843   )\r
1844 {\r
1845   UINTN Index;\r
1846   //\r
1847   // Remove the specified text-in device data structure from the Text In List,\r
1848   // and rearrange the remaining data structures in the Text In List.\r
1849   //\r
1850   for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {\r
1851     if (Private->TextInExList[Index] == TextInEx) {\r
1852       for (Index = Index; Index < Private->CurrentNumberOfExConsoles - 1; Index++) {\r
1853         Private->TextInExList[Index] = Private->TextInExList[Index + 1];\r
1854       }\r
1855 \r
1856       Private->CurrentNumberOfExConsoles--;\r
1857       return EFI_SUCCESS;\r
1858     }\r
1859   }\r
1860 \r
1861   return EFI_NOT_FOUND;\r
1862 }\r
1863 \r
1864 EFI_STATUS\r
1865 ConSplitterSimplePointerAddDevice (\r
1866   IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,\r
1867   IN  EFI_SIMPLE_POINTER_PROTOCOL     *SimplePointer\r
1868   )\r
1869 /*++\r
1870 \r
1871 Routine Description:\r
1872 \r
1873 Arguments:\r
1874 \r
1875 Returns:\r
1876 \r
1877   EFI_OUT_OF_RESOURCES\r
1878   EFI_SUCCESS\r
1879 \r
1880 --*/\r
1881 {\r
1882   EFI_STATUS  Status;\r
1883 \r
1884   //\r
1885   // If the Text In List is full, enlarge it by calling growbuffer().\r
1886   //\r
1887   if (Private->CurrentNumberOfPointers >= Private->PointerListCount) {\r
1888     Status = ConSplitterGrowBuffer (\r
1889               sizeof (EFI_SIMPLE_POINTER_PROTOCOL *),\r
1890               &Private->PointerListCount,\r
1891               (VOID **) &Private->PointerList\r
1892               );\r
1893     if (EFI_ERROR (Status)) {\r
1894       return EFI_OUT_OF_RESOURCES;\r
1895     }\r
1896   }\r
1897   //\r
1898   // Add the new text-in device data structure into the Text In List.\r
1899   //\r
1900   Private->PointerList[Private->CurrentNumberOfPointers] = SimplePointer;\r
1901   Private->CurrentNumberOfPointers++;\r
1902   return EFI_SUCCESS;\r
1903 }\r
1904 \r
1905 EFI_STATUS\r
1906 ConSplitterSimplePointerDeleteDevice (\r
1907   IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,\r
1908   IN  EFI_SIMPLE_POINTER_PROTOCOL     *SimplePointer\r
1909   )\r
1910 /*++\r
1911 \r
1912 Routine Description:\r
1913 \r
1914 Arguments:\r
1915 \r
1916 Returns:\r
1917 \r
1918   None\r
1919 \r
1920 --*/\r
1921 {\r
1922   UINTN Index;\r
1923   //\r
1924   // Remove the specified text-in device data structure from the Text In List,\r
1925   // and rearrange the remaining data structures in the Text In List.\r
1926   //\r
1927   for (Index = 0; Index < Private->CurrentNumberOfPointers; Index++) {\r
1928     if (Private->PointerList[Index] == SimplePointer) {\r
1929       for (Index = Index; Index < Private->CurrentNumberOfPointers - 1; Index++) {\r
1930         Private->PointerList[Index] = Private->PointerList[Index + 1];\r
1931       }\r
1932 \r
1933       Private->CurrentNumberOfPointers--;\r
1934       return EFI_SUCCESS;\r
1935     }\r
1936   }\r
1937 \r
1938   return EFI_NOT_FOUND;\r
1939 }\r
1940 \r
1941 EFI_STATUS\r
1942 ConSplitterAbsolutePointerAddDevice (\r
1943   IN  TEXT_IN_SPLITTER_PRIVATE_DATA     *Private,\r
1944   IN  EFI_ABSOLUTE_POINTER_PROTOCOL     *AbsolutePointer\r
1945   )\r
1946 /*++\r
1947 \r
1948 Routine Description:\r
1949 \r
1950 Arguments:\r
1951 \r
1952 Returns:\r
1953 \r
1954   EFI_OUT_OF_RESOURCES\r
1955   EFI_SUCCESS\r
1956 \r
1957 --*/\r
1958 {\r
1959   EFI_STATUS  Status;\r
1960 \r
1961   //\r
1962   // If the Absolute Pointer List is full, enlarge it by calling growbuffer().\r
1963   //\r
1964   if (Private->CurrentNumberOfAbsolutePointers >= Private->AbsolutePointerListCount) {\r
1965     Status = ConSplitterGrowBuffer (\r
1966               sizeof (EFI_ABSOLUTE_POINTER_PROTOCOL *),\r
1967               &Private->AbsolutePointerListCount,\r
1968               (VOID **) &Private->AbsolutePointerList\r
1969               );\r
1970     if (EFI_ERROR (Status)) {\r
1971       return EFI_OUT_OF_RESOURCES;\r
1972     }\r
1973   }\r
1974   //\r
1975   // Add the new text-in device data structure into the Text In List.\r
1976   //\r
1977   Private->AbsolutePointerList[Private->CurrentNumberOfAbsolutePointers] = AbsolutePointer;\r
1978   Private->CurrentNumberOfAbsolutePointers++;\r
1979   return EFI_SUCCESS;\r
1980 }\r
1981 \r
1982 EFI_STATUS\r
1983 ConSplitterAbsolutePointerDeleteDevice (\r
1984   IN  TEXT_IN_SPLITTER_PRIVATE_DATA     *Private,\r
1985   IN  EFI_ABSOLUTE_POINTER_PROTOCOL     *AbsolutePointer\r
1986   )\r
1987 /*++\r
1988 \r
1989 Routine Description:\r
1990 \r
1991 Arguments:\r
1992 \r
1993 Returns:\r
1994 \r
1995   None\r
1996 \r
1997 --*/\r
1998 {\r
1999   UINTN Index;\r
2000   //\r
2001   // Remove the specified text-in device data structure from the Text In List,\r
2002   // and rearrange the remaining data structures in the Text In List.\r
2003   //\r
2004   for (Index = 0; Index < Private->CurrentNumberOfAbsolutePointers; Index++) {\r
2005     if (Private->AbsolutePointerList[Index] == AbsolutePointer) {\r
2006       for (Index = Index; Index < Private->CurrentNumberOfAbsolutePointers - 1; Index++) {\r
2007         Private->AbsolutePointerList[Index] = Private->AbsolutePointerList[Index + 1];\r
2008       }\r
2009 \r
2010       Private->CurrentNumberOfAbsolutePointers--;\r
2011       return EFI_SUCCESS;\r
2012     }\r
2013   }\r
2014 \r
2015   return EFI_NOT_FOUND;\r
2016 }\r
2017 \r
2018 STATIC\r
2019 EFI_STATUS\r
2020 ConSplitterGrowMapTable (\r
2021   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private\r
2022   )\r
2023 /*++\r
2024 \r
2025 Routine Description:\r
2026 \r
2027 Arguments:\r
2028 \r
2029 Returns:\r
2030 \r
2031   None\r
2032 \r
2033 --*/\r
2034 {\r
2035   UINTN Size;\r
2036   UINTN NewSize;\r
2037   UINTN TotalSize;\r
2038   INT32 *TextOutModeMap;\r
2039   INT32 *OldTextOutModeMap;\r
2040   INT32 *SrcAddress;\r
2041   INT32 Index;\r
2042 \r
2043   NewSize           = Private->TextOutListCount * sizeof (INT32);\r
2044   OldTextOutModeMap = Private->TextOutModeMap;\r
2045   TotalSize         = NewSize * Private->TextOutQueryDataCount;\r
2046 \r
2047   TextOutModeMap    = AllocateZeroPool (TotalSize);\r
2048   if (TextOutModeMap == NULL) {\r
2049     return EFI_OUT_OF_RESOURCES;\r
2050   }\r
2051 \r
2052   SetMem (TextOutModeMap, TotalSize, 0xFF);\r
2053   Private->TextOutModeMap = TextOutModeMap;\r
2054 \r
2055   //\r
2056   // If TextOutList has been enlarged, need to realloc the mode map table\r
2057   // The mode map table is regarded as a two dimension array.\r
2058   //\r
2059   //                         Old                    New\r
2060   //  0   ---------> TextOutListCount ----> TextOutListCount\r
2061   //  |   -------------------------------------------\r
2062   //  |  |                    |                      |\r
2063   //  |  |                    |                      |\r
2064   //  |  |                    |                      |\r
2065   //  |  |                    |                      |\r
2066   //  |  |                    |                      |\r
2067   // \/  |                    |                      |\r
2068   //      -------------------------------------------\r
2069   // QueryDataCount\r
2070   //\r
2071   if (OldTextOutModeMap != NULL) {\r
2072 \r
2073     Size        = Private->CurrentNumberOfConsoles * sizeof (INT32);\r
2074     Index       = 0;\r
2075     SrcAddress  = OldTextOutModeMap;\r
2076 \r
2077     //\r
2078     // Copy the old data to the new one\r
2079     //\r
2080     while (Index < Private->TextOutMode.MaxMode) {\r
2081       CopyMem (TextOutModeMap, SrcAddress, Size);\r
2082       TextOutModeMap += NewSize;\r
2083       SrcAddress += Size;\r
2084       Index++;\r
2085     }\r
2086     //\r
2087     // Free the old buffer\r
2088     //\r
2089     FreePool (OldTextOutModeMap);\r
2090   }\r
2091 \r
2092   return EFI_SUCCESS;\r
2093 }\r
2094 \r
2095 STATIC\r
2096 EFI_STATUS\r
2097 ConSplitterAddOutputMode (\r
2098   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA     *Private,\r
2099   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *TextOut\r
2100   )\r
2101 /*++\r
2102 \r
2103 Routine Description:\r
2104 \r
2105 Arguments:\r
2106 \r
2107 Returns:\r
2108 \r
2109   None\r
2110 \r
2111 --*/\r
2112 {\r
2113   EFI_STATUS  Status;\r
2114   INT32       MaxMode;\r
2115   INT32       Mode;\r
2116   UINTN       Index;\r
2117 \r
2118   MaxMode                       = TextOut->Mode->MaxMode;\r
2119   Private->TextOutMode.MaxMode  = MaxMode;\r
2120 \r
2121   //\r
2122   // Grow the buffer if query data buffer is not large enough to\r
2123   // hold all the mode supported by the first console.\r
2124   //\r
2125   while (MaxMode > (INT32) Private->TextOutQueryDataCount) {\r
2126     Status = ConSplitterGrowBuffer (\r
2127               sizeof (TEXT_OUT_SPLITTER_QUERY_DATA),\r
2128               &Private->TextOutQueryDataCount,\r
2129               (VOID **) &Private->TextOutQueryData\r
2130               );\r
2131     if (EFI_ERROR (Status)) {\r
2132       return EFI_OUT_OF_RESOURCES;\r
2133     }\r
2134   }\r
2135   //\r
2136   // Allocate buffer for the output mode map\r
2137   //\r
2138   Status = ConSplitterGrowMapTable (Private);\r
2139   if (EFI_ERROR (Status)) {\r
2140     return EFI_OUT_OF_RESOURCES;\r
2141   }\r
2142   //\r
2143   // As the first textout device, directly add the mode in to QueryData\r
2144   // and at the same time record the mapping between QueryData and TextOut.\r
2145   //\r
2146   Mode  = 0;\r
2147   Index = 0;\r
2148   while (Mode < MaxMode) {\r
2149     TextOut->QueryMode (\r
2150               TextOut,\r
2151               Mode,\r
2152               &Private->TextOutQueryData[Mode].Columns,\r
2153               &Private->TextOutQueryData[Mode].Rows\r
2154               );\r
2155     Private->TextOutModeMap[Index] = Mode;\r
2156     Mode++;\r
2157     Index += Private->TextOutListCount;\r
2158   }\r
2159 \r
2160   return EFI_SUCCESS;\r
2161 }\r
2162 \r
2163 STATIC\r
2164 VOID\r
2165 ConSplitterGetIntersection (\r
2166   IN  INT32                           *TextOutModeMap,\r
2167   IN  INT32                           *NewlyAddedMap,\r
2168   IN  UINTN                           MapStepSize,\r
2169   IN  UINTN                           NewMapStepSize,\r
2170   OUT INT32                           *MaxMode,\r
2171   OUT INT32                           *CurrentMode\r
2172   )\r
2173 {\r
2174   INT32 Index;\r
2175   INT32 *CurrentMapEntry;\r
2176   INT32 *NextMapEntry;\r
2177   INT32 CurrentMaxMode;\r
2178   INT32 Mode;\r
2179 \r
2180   Index           = 0;\r
2181   CurrentMapEntry = TextOutModeMap;\r
2182   NextMapEntry    = TextOutModeMap;\r
2183   CurrentMaxMode  = *MaxMode;\r
2184   Mode            = *CurrentMode;\r
2185 \r
2186   while (Index < CurrentMaxMode) {\r
2187     if (*NewlyAddedMap == -1) {\r
2188       //\r
2189       // This mode is not supported any more. Remove it. Special care\r
2190       // must be taken as this remove will also affect current mode;\r
2191       //\r
2192       if (Index == *CurrentMode) {\r
2193         Mode = -1;\r
2194       } else if (Index < *CurrentMode) {\r
2195         Mode--;\r
2196       }\r
2197       (*MaxMode)--;\r
2198     } else {\r
2199       if (CurrentMapEntry != NextMapEntry) {\r
2200         CopyMem (NextMapEntry, CurrentMapEntry, MapStepSize * sizeof (INT32));\r
2201       }\r
2202 \r
2203       NextMapEntry += MapStepSize;\r
2204     }\r
2205 \r
2206     CurrentMapEntry += MapStepSize;\r
2207     NewlyAddedMap += NewMapStepSize;\r
2208     Index++;\r
2209   }\r
2210 \r
2211   *CurrentMode = Mode;\r
2212 \r
2213   return ;\r
2214 }\r
2215 \r
2216 STATIC\r
2217 VOID\r
2218 ConSplitterSyncOutputMode (\r
2219   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA     *Private,\r
2220   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *TextOut\r
2221   )\r
2222 /*++\r
2223 \r
2224 Routine Description:\r
2225 \r
2226 Arguments:\r
2227   Private - Private data structure.\r
2228   TextOut - Text Out Protocol.\r
2229 Returns:\r
2230 \r
2231   None\r
2232 \r
2233 --*/\r
2234 {\r
2235   INT32                         CurrentMaxMode;\r
2236   INT32                         Mode;\r
2237   INT32                         Index;\r
2238   INT32                         *TextOutModeMap;\r
2239   INT32                         *MapTable;\r
2240   TEXT_OUT_SPLITTER_QUERY_DATA  *TextOutQueryData;\r
2241   UINTN                         Rows;\r
2242   UINTN                         Columns;\r
2243   UINTN                         StepSize;\r
2244 \r
2245   //\r
2246   // Must make sure that current mode won't change even if mode number changes\r
2247   //\r
2248   CurrentMaxMode    = Private->TextOutMode.MaxMode;\r
2249   TextOutModeMap    = Private->TextOutModeMap;\r
2250   StepSize          = Private->TextOutListCount;\r
2251   TextOutQueryData  = Private->TextOutQueryData;\r
2252 \r
2253   //\r
2254   // Query all the mode that the newly added TextOut supports\r
2255   //\r
2256   Mode      = 0;\r
2257   MapTable  = TextOutModeMap + Private->CurrentNumberOfConsoles;\r
2258   while (Mode < TextOut->Mode->MaxMode) {\r
2259     TextOut->QueryMode (TextOut, Mode, &Columns, &Rows);\r
2260 \r
2261     //\r
2262     // Search the QueryData database to see if they intersects\r
2263     //\r
2264     Index = 0;\r
2265     while (Index < CurrentMaxMode) {\r
2266       if ((TextOutQueryData[Index].Rows == Rows) && (TextOutQueryData[Index].Columns == Columns)) {\r
2267         MapTable[Index * StepSize] = Mode;\r
2268         break;\r
2269       }\r
2270 \r
2271       Index++;\r
2272     }\r
2273 \r
2274     Mode++;\r
2275   }\r
2276   //\r
2277   // Now search the TextOutModeMap table to find the intersection of supported\r
2278   // mode between ConSplitter and the newly added device.\r
2279   //\r
2280   ConSplitterGetIntersection (\r
2281     TextOutModeMap,\r
2282     MapTable,\r
2283     StepSize,\r
2284     StepSize,\r
2285     &Private->TextOutMode.MaxMode,\r
2286     &Private->TextOutMode.Mode\r
2287     );\r
2288 \r
2289   return ;\r
2290 }\r
2291 \r
2292 STATIC\r
2293 EFI_STATUS\r
2294 ConSplitterGetIntersectionBetweenConOutAndStrErr (\r
2295   VOID\r
2296   )\r
2297 /*++\r
2298 \r
2299 Routine Description:\r
2300 \r
2301 Arguments:\r
2302 \r
2303 Returns:\r
2304 \r
2305   None\r
2306   EFI_OUT_OF_RESOURCES\r
2307 \r
2308 --*/\r
2309 {\r
2310   UINTN                         ConOutNumOfConsoles;\r
2311   UINTN                         StdErrNumOfConsoles;\r
2312   TEXT_OUT_AND_GOP_DATA         *ConOutTextOutList;\r
2313   TEXT_OUT_AND_GOP_DATA         *StdErrTextOutList;\r
2314   UINTN                         Indexi;\r
2315   UINTN                         Indexj;\r
2316   UINTN                         Rows;\r
2317   UINTN                         Columns;\r
2318   INT32                         ConOutMaxMode;\r
2319   INT32                         StdErrMaxMode;\r
2320   INT32                         Mode;\r
2321   INT32                         Index;\r
2322   INT32                         *ConOutModeMap;\r
2323   INT32                         *StdErrModeMap;\r
2324   INT32                         *ConOutMapTable;\r
2325   INT32                         *StdErrMapTable;\r
2326   TEXT_OUT_SPLITTER_QUERY_DATA  *ConOutQueryData;\r
2327   TEXT_OUT_SPLITTER_QUERY_DATA  *StdErrQueryData;\r
2328   BOOLEAN                       FoundTheSameTextOut;\r
2329   UINTN                         ConOutMapTableSize;\r
2330   UINTN                         StdErrMapTableSize;\r
2331 \r
2332   ConOutNumOfConsoles = mConOut.CurrentNumberOfConsoles;\r
2333   StdErrNumOfConsoles = mStdErr.CurrentNumberOfConsoles;\r
2334   ConOutTextOutList   = mConOut.TextOutList;\r
2335   StdErrTextOutList   = mStdErr.TextOutList;\r
2336 \r
2337   Indexi              = 0;\r
2338   FoundTheSameTextOut = FALSE;\r
2339   while ((Indexi < ConOutNumOfConsoles) && (!FoundTheSameTextOut)) {\r
2340     Indexj = 0;\r
2341     while (Indexj < StdErrNumOfConsoles) {\r
2342       if (ConOutTextOutList->TextOut == StdErrTextOutList->TextOut) {\r
2343         FoundTheSameTextOut = TRUE;\r
2344         break;\r
2345       }\r
2346 \r
2347       Indexj++;\r
2348       StdErrTextOutList++;\r
2349     }\r
2350 \r
2351     Indexi++;\r
2352     ConOutTextOutList++;\r
2353   }\r
2354 \r
2355   if (!FoundTheSameTextOut) {\r
2356     return EFI_SUCCESS;\r
2357   }\r
2358   //\r
2359   // Must make sure that current mode won't change even if mode number changes\r
2360   //\r
2361   ConOutMaxMode     = mConOut.TextOutMode.MaxMode;\r
2362   ConOutModeMap     = mConOut.TextOutModeMap;\r
2363   ConOutQueryData   = mConOut.TextOutQueryData;\r
2364 \r
2365   StdErrMaxMode     = mStdErr.TextOutMode.MaxMode;\r
2366   StdErrModeMap     = mStdErr.TextOutModeMap;\r
2367   StdErrQueryData   = mStdErr.TextOutQueryData;\r
2368 \r
2369   //\r
2370   // Allocate the map table and set the map table's index to -1.\r
2371   //\r
2372   ConOutMapTableSize  = ConOutMaxMode * sizeof (INT32);\r
2373   ConOutMapTable      = AllocateZeroPool (ConOutMapTableSize);\r
2374   if (ConOutMapTable == NULL) {\r
2375     return EFI_OUT_OF_RESOURCES;\r
2376   }\r
2377 \r
2378   SetMem (ConOutMapTable, ConOutMapTableSize, 0xFF);\r
2379 \r
2380   StdErrMapTableSize  = StdErrMaxMode * sizeof (INT32);\r
2381   StdErrMapTable      = AllocateZeroPool (StdErrMapTableSize);\r
2382   if (StdErrMapTable == NULL) {\r
2383     return EFI_OUT_OF_RESOURCES;\r
2384   }\r
2385 \r
2386   SetMem (StdErrMapTable, StdErrMapTableSize, 0xFF);\r
2387 \r
2388   //\r
2389   // Find the intersection of the two set of modes. If they actually intersect, the\r
2390   // correponding entry in the map table is set to 1.\r
2391   //\r
2392   Mode = 0;\r
2393   while (Mode < ConOutMaxMode) {\r
2394     //\r
2395     // Search the other's QueryData database to see if they intersect\r
2396     //\r
2397     Index   = 0;\r
2398     Rows    = ConOutQueryData[Mode].Rows;\r
2399     Columns = ConOutQueryData[Mode].Columns;\r
2400     while (Index < StdErrMaxMode) {\r
2401       if ((StdErrQueryData[Index].Rows == Rows) && (StdErrQueryData[Index].Columns == Columns)) {\r
2402         ConOutMapTable[Mode]  = 1;\r
2403         StdErrMapTable[Index] = 1;\r
2404         break;\r
2405       }\r
2406 \r
2407       Index++;\r
2408     }\r
2409 \r
2410     Mode++;\r
2411   }\r
2412   //\r
2413   // Now search the TextOutModeMap table to find the intersection of supported\r
2414   // mode between ConSplitter and the newly added device.\r
2415   //\r
2416   ConSplitterGetIntersection (\r
2417     ConOutModeMap,\r
2418     ConOutMapTable,\r
2419     mConOut.TextOutListCount,\r
2420     1,\r
2421     &(mConOut.TextOutMode.MaxMode),\r
2422     &(mConOut.TextOutMode.Mode)\r
2423     );\r
2424   if (mConOut.TextOutMode.Mode < 0) {\r
2425     mConOut.TextOut.SetMode (&(mConOut.TextOut), 0);\r
2426   }\r
2427 \r
2428   ConSplitterGetIntersection (\r
2429     StdErrModeMap,\r
2430     StdErrMapTable,\r
2431     mStdErr.TextOutListCount,\r
2432     1,\r
2433     &(mStdErr.TextOutMode.MaxMode),\r
2434     &(mStdErr.TextOutMode.Mode)\r
2435     );\r
2436   if (mStdErr.TextOutMode.Mode < 0) {\r
2437     mStdErr.TextOut.SetMode (&(mStdErr.TextOut), 0);\r
2438   }\r
2439 \r
2440   FreePool (ConOutMapTable);\r
2441   FreePool (StdErrMapTable);\r
2442 \r
2443   return EFI_SUCCESS;\r
2444 }\r
2445 \r
2446 STATIC\r
2447 EFI_STATUS\r
2448 ConSplitterAddGraphicsOutputMode (\r
2449   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private,\r
2450   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL    *GraphicsOutput,\r
2451   IN  EFI_UGA_DRAW_PROTOCOL           *UgaDraw\r
2452   )\r
2453 /*++\r
2454 \r
2455 Routine Description:\r
2456 \r
2457 Arguments:\r
2458 \r
2459 Returns:\r
2460 \r
2461   None\r
2462 \r
2463 --*/\r
2464 {\r
2465   EFI_STATUS                           Status;\r
2466   UINTN                                Index;\r
2467   TEXT_OUT_GOP_MODE                    *Mode;\r
2468   UINTN                                SizeOfInfo;\r
2469   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;\r
2470   EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE    *CurrentGraphicsOutputMode;\r
2471   TEXT_OUT_GOP_MODE                    *ModeBuffer;\r
2472   TEXT_OUT_GOP_MODE                    *MatchedMode;\r
2473   UINTN                                NumberIndex;\r
2474   BOOLEAN                              Match;\r
2475 \r
2476   if ((GraphicsOutput == NULL) && (UgaDraw == NULL)) {\r
2477     return EFI_UNSUPPORTED;\r
2478   }\r
2479 \r
2480   CurrentGraphicsOutputMode = Private->GraphicsOutput.Mode;\r
2481 \r
2482   if (GraphicsOutput != NULL) {\r
2483     if (Private->CurrentNumberOfGraphicsOutput == 0) {\r
2484         //\r
2485         // This is the first Graphics Output device added\r
2486         //\r
2487         CurrentGraphicsOutputMode->MaxMode = GraphicsOutput->Mode->MaxMode;\r
2488         CurrentGraphicsOutputMode->Mode = GraphicsOutput->Mode->Mode;\r
2489         CopyMem (CurrentGraphicsOutputMode->Info, GraphicsOutput->Mode->Info, GraphicsOutput->Mode->SizeOfInfo);\r
2490         CurrentGraphicsOutputMode->SizeOfInfo = GraphicsOutput->Mode->SizeOfInfo;\r
2491         CurrentGraphicsOutputMode->FrameBufferBase = GraphicsOutput->Mode->FrameBufferBase;\r
2492         CurrentGraphicsOutputMode->FrameBufferSize = GraphicsOutput->Mode->FrameBufferSize;\r
2493 \r
2494         //\r
2495         // Allocate resource for the private mode buffer\r
2496         //\r
2497         ModeBuffer = AllocatePool (sizeof (TEXT_OUT_GOP_MODE) * GraphicsOutput->Mode->MaxMode);\r
2498         if (ModeBuffer == NULL) {\r
2499           return EFI_OUT_OF_RESOURCES;\r
2500         }\r
2501         FreePool (Private->GraphicsOutputModeBuffer);\r
2502         Private->GraphicsOutputModeBuffer = ModeBuffer;\r
2503 \r
2504         //\r
2505         // Store all supported display modes to the private mode buffer\r
2506         //\r
2507         Mode = ModeBuffer;\r
2508         for (Index = 0; Index < GraphicsOutput->Mode->MaxMode; Index++) {\r
2509           Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) Index, &SizeOfInfo, &Info);\r
2510           if (EFI_ERROR (Status)) {\r
2511             return Status;\r
2512           }\r
2513           Mode->HorizontalResolution = Info->HorizontalResolution;\r
2514           Mode->VerticalResolution = Info->VerticalResolution;\r
2515           Mode++;\r
2516           FreePool (Info);\r
2517         }\r
2518     } else {\r
2519       //\r
2520       // Check intersection of display mode\r
2521       //\r
2522       ModeBuffer = AllocatePool (sizeof (TEXT_OUT_GOP_MODE) * CurrentGraphicsOutputMode->MaxMode);\r
2523       if (ModeBuffer == NULL) {\r
2524         return EFI_OUT_OF_RESOURCES;\r
2525       }\r
2526 \r
2527       MatchedMode = ModeBuffer;\r
2528       Mode = &Private->GraphicsOutputModeBuffer[0];\r
2529       for (Index = 0; Index < CurrentGraphicsOutputMode->MaxMode; Index++) {\r
2530         Match = FALSE;\r
2531 \r
2532         for (NumberIndex = 0; NumberIndex < GraphicsOutput->Mode->MaxMode; NumberIndex++) {\r
2533           Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) NumberIndex, &SizeOfInfo, &Info);\r
2534           if (EFI_ERROR (Status)) {\r
2535             return Status;\r
2536           }\r
2537           if ((Info->HorizontalResolution == Mode->HorizontalResolution) &&\r
2538               (Info->VerticalResolution == Mode->VerticalResolution)){\r
2539             Match = TRUE;\r
2540             FreePool (Info);\r
2541             break;\r
2542           }\r
2543           FreePool (Info);\r
2544         }\r
2545 \r
2546         if (Match) {\r
2547           CopyMem (MatchedMode, Mode, sizeof (TEXT_OUT_GOP_MODE));\r
2548           MatchedMode++;\r
2549         }\r
2550 \r
2551         Mode++;\r
2552       }\r
2553 \r
2554       //\r
2555       // Drop the old mode buffer, assign it to a new one\r
2556       //\r
2557       FreePool (Private->GraphicsOutputModeBuffer);\r
2558       Private->GraphicsOutputModeBuffer = ModeBuffer;\r
2559 \r
2560       //\r
2561       // Physical frame buffer is no longer available when there are more than one physical GOP devices\r
2562       //\r
2563       CurrentGraphicsOutputMode->MaxMode = (UINT32) (((UINTN) MatchedMode - (UINTN) ModeBuffer) / sizeof (TEXT_OUT_GOP_MODE));\r
2564       CurrentGraphicsOutputMode->Info->PixelFormat = PixelBltOnly;\r
2565       ZeroMem (&CurrentGraphicsOutputMode->Info->PixelInformation, sizeof (EFI_PIXEL_BITMASK));\r
2566       CurrentGraphicsOutputMode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);\r
2567       CurrentGraphicsOutputMode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) NULL;\r
2568       CurrentGraphicsOutputMode->FrameBufferSize = 0;\r
2569     }\r
2570 \r
2571     //\r
2572     // Select a prefered Display mode 800x600\r
2573     //\r
2574     for (Index = 0; Index < CurrentGraphicsOutputMode->MaxMode; Index++) {\r
2575       Mode = &Private->GraphicsOutputModeBuffer[Index];\r
2576       if ((Mode->HorizontalResolution == 800) && (Mode->VerticalResolution == 600)) {\r
2577         break;\r
2578       }\r
2579     }\r
2580     //\r
2581     // Prefered mode is not found, set to mode 0\r
2582     //\r
2583     if (Index >= CurrentGraphicsOutputMode->MaxMode) {\r
2584       Index = 0;\r
2585     }\r
2586 \r
2587     //\r
2588     // Current mode number may need update now, so set it to an invalide mode number\r
2589     //\r
2590     CurrentGraphicsOutputMode->Mode = 0xffff;\r
2591   } else {\r
2592     //\r
2593     // For UGA device, it's inconvenient to retrieve all the supported display modes.\r
2594     // To simplify the implementation, only add one resolution(800x600, 32bit color depth) as defined in UEFI spec\r
2595     //\r
2596     CurrentGraphicsOutputMode->MaxMode = 1;\r
2597     CurrentGraphicsOutputMode->Info->Version = 0;\r
2598     CurrentGraphicsOutputMode->Info->HorizontalResolution = 800;\r
2599     CurrentGraphicsOutputMode->Info->VerticalResolution = 600;\r
2600     CurrentGraphicsOutputMode->Info->PixelFormat = PixelBltOnly;\r
2601     CurrentGraphicsOutputMode->Info->PixelsPerScanLine = 800;\r
2602     CurrentGraphicsOutputMode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);\r
2603     CurrentGraphicsOutputMode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) NULL;\r
2604     CurrentGraphicsOutputMode->FrameBufferSize = 0;\r
2605 \r
2606     //\r
2607     // Update the private mode buffer\r
2608     //\r
2609     ModeBuffer = &Private->GraphicsOutputModeBuffer[0];\r
2610     ModeBuffer->HorizontalResolution = 800;\r
2611     ModeBuffer->VerticalResolution   = 600;\r
2612 \r
2613     //\r
2614     // Current mode is unknow now, set it to an invalid mode number 0xffff\r
2615     //\r
2616     CurrentGraphicsOutputMode->Mode = 0xffff;\r
2617     Index = 0;\r
2618   }\r
2619 \r
2620   //\r
2621   // Force GraphicsOutput mode to be set,\r
2622   // regardless whether the console is in EfiConsoleControlScreenGraphics or EfiConsoleControlScreenText mode\r
2623   //\r
2624   Private->HardwareNeedsStarting = TRUE;\r
2625   Status = Private->GraphicsOutput.SetMode (&Private->GraphicsOutput, (UINT32) Index);\r
2626 \r
2627   Private->CurrentNumberOfGraphicsOutput++;\r
2628 \r
2629   return Status;\r
2630 }\r
2631 \r
2632 EFI_STATUS\r
2633 ConSplitterTextOutAddDevice (\r
2634   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA     *Private,\r
2635   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *TextOut,\r
2636   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL       *GraphicsOutput,\r
2637   IN  EFI_UGA_DRAW_PROTOCOL              *UgaDraw\r
2638   )\r
2639 /*++\r
2640 \r
2641 Routine Description:\r
2642 \r
2643 Arguments:\r
2644 \r
2645 Returns:\r
2646 \r
2647   None\r
2648 \r
2649 --*/\r
2650 {\r
2651   EFI_STATUS            Status;\r
2652   UINTN                 CurrentNumOfConsoles;\r
2653   INT32                 CurrentMode;\r
2654   INT32                 MaxMode;\r
2655   TEXT_OUT_AND_GOP_DATA *TextAndGop;\r
2656 \r
2657   Status                = EFI_SUCCESS;\r
2658   CurrentNumOfConsoles  = Private->CurrentNumberOfConsoles;\r
2659 \r
2660   //\r
2661   // If the Text Out List is full, enlarge it by calling growbuffer().\r
2662   //\r
2663   while (CurrentNumOfConsoles >= Private->TextOutListCount) {\r
2664     Status = ConSplitterGrowBuffer (\r
2665               sizeof (TEXT_OUT_AND_GOP_DATA),\r
2666               &Private->TextOutListCount,\r
2667               (VOID **) &Private->TextOutList\r
2668               );\r
2669     if (EFI_ERROR (Status)) {\r
2670       return EFI_OUT_OF_RESOURCES;\r
2671     }\r
2672     //\r
2673     // Also need to reallocate the TextOutModeMap table\r
2674     //\r
2675     Status = ConSplitterGrowMapTable (Private);\r
2676     if (EFI_ERROR (Status)) {\r
2677       return EFI_OUT_OF_RESOURCES;\r
2678     }\r
2679   }\r
2680 \r
2681   TextAndGop          = &Private->TextOutList[CurrentNumOfConsoles];\r
2682 \r
2683   TextAndGop->TextOut = TextOut;\r
2684   TextAndGop->GraphicsOutput = GraphicsOutput;\r
2685   TextAndGop->UgaDraw = UgaDraw;\r
2686 \r
2687   if ((GraphicsOutput == NULL) && (UgaDraw == NULL)) {\r
2688     //\r
2689     // If No UGA device then use the ConOut device\r
2690     //\r
2691     TextAndGop->TextOutEnabled = TRUE;\r
2692   } else {\r
2693     //\r
2694     // If UGA device use ConOut device only used if UGA screen is in Text mode\r
2695     //\r
2696     TextAndGop->TextOutEnabled = (BOOLEAN) (Private->ConsoleOutputMode == EfiConsoleControlScreenText);\r
2697   }\r
2698 \r
2699   if (CurrentNumOfConsoles == 0) {\r
2700     //\r
2701     // Add the first device's output mode to console splitter's mode list\r
2702     //\r
2703     Status = ConSplitterAddOutputMode (Private, TextOut);\r
2704   } else {\r
2705     ConSplitterSyncOutputMode (Private, TextOut);\r
2706   }\r
2707 \r
2708   Private->CurrentNumberOfConsoles++;\r
2709 \r
2710   //\r
2711   // Scan both TextOutList, for the intersection TextOut device\r
2712   // maybe both ConOut and StdErr incorporate the same Text Out\r
2713   // device in them, thus the output of both should be synced.\r
2714   //\r
2715   ConSplitterGetIntersectionBetweenConOutAndStrErr ();\r
2716 \r
2717   CurrentMode = Private->TextOutMode.Mode;\r
2718   MaxMode     = Private->TextOutMode.MaxMode;\r
2719   ASSERT (MaxMode >= 1);\r
2720 \r
2721   if (FeaturePcdGet (PcdConOutGopSupport)) {\r
2722     if ((GraphicsOutput != NULL) || (UgaDraw != NULL)) {\r
2723       ConSplitterAddGraphicsOutputMode (Private, GraphicsOutput, UgaDraw);\r
2724     }\r
2725   }\r
2726 \r
2727   if (Private->ConsoleOutputMode == EfiConsoleControlScreenGraphics && GraphicsOutput != NULL) {\r
2728     //\r
2729     // We just added a new UGA device in graphics mode\r
2730     //\r
2731     if (FeaturePcdGet (PcdConOutGopSupport)) {\r
2732       DevNullGopSync (Private, TextAndGop->GraphicsOutput, TextAndGop->UgaDraw);\r
2733     } else if (FeaturePcdGet (PcdConOutUgaSupport)) {\r
2734       DevNullUgaSync (Private, TextAndGop->GraphicsOutput, TextAndGop->UgaDraw);\r
2735     }\r
2736   } else if ((CurrentMode >= 0) && ((GraphicsOutput != NULL) || (UgaDraw != NULL)) && (CurrentMode < Private->TextOutMode.MaxMode)) {\r
2737     //\r
2738     // The new console supports the same mode of the current console so sync up\r
2739     //\r
2740     DevNullSyncGopStdOut (Private);\r
2741   } else {\r
2742     //\r
2743     // If ConOut, then set the mode to Mode #0 which us 80 x 25\r
2744     //\r
2745     Private->TextOut.SetMode (&Private->TextOut, 0);\r
2746   }\r
2747 \r
2748   return Status;\r
2749 }\r
2750 \r
2751 EFI_STATUS\r
2752 ConSplitterTextOutDeleteDevice (\r
2753   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA     *Private,\r
2754   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *TextOut\r
2755   )\r
2756 /*++\r
2757 \r
2758 Routine Description:\r
2759 \r
2760 Arguments:\r
2761 \r
2762 Returns:\r
2763 \r
2764   None\r
2765 \r
2766 --*/\r
2767 {\r
2768   INT32                 Index;\r
2769   UINTN                 CurrentNumOfConsoles;\r
2770   TEXT_OUT_AND_GOP_DATA *TextOutList;\r
2771   EFI_STATUS            Status;\r
2772 \r
2773   //\r
2774   // Remove the specified text-out device data structure from the Text out List,\r
2775   // and rearrange the remaining data structures in the Text out List.\r
2776   //\r
2777   CurrentNumOfConsoles  = Private->CurrentNumberOfConsoles;\r
2778   Index                 = (INT32) CurrentNumOfConsoles - 1;\r
2779   TextOutList           = Private->TextOutList;\r
2780   while (Index >= 0) {\r
2781     if (TextOutList->TextOut == TextOut) {\r
2782       CopyMem (TextOutList, TextOutList + 1, sizeof (TEXT_OUT_AND_GOP_DATA) * Index);\r
2783       CurrentNumOfConsoles--;\r
2784       break;\r
2785     }\r
2786 \r
2787     Index--;\r
2788     TextOutList++;\r
2789   }\r
2790   //\r
2791   // The specified TextOut is not managed by the ConSplitter driver\r
2792   //\r
2793   if (Index < 0) {\r
2794     return EFI_NOT_FOUND;\r
2795   }\r
2796 \r
2797   if (CurrentNumOfConsoles == 0) {\r
2798     //\r
2799     // If the number of consoles is zero clear the Dev NULL device\r
2800     //\r
2801     Private->CurrentNumberOfConsoles      = 0;\r
2802     Private->TextOutMode.MaxMode          = 1;\r
2803     Private->TextOutQueryData[0].Columns  = 80;\r
2804     Private->TextOutQueryData[0].Rows     = 25;\r
2805     DevNullTextOutSetMode (Private, 0);\r
2806 \r
2807     return EFI_SUCCESS;\r
2808   }\r
2809   //\r
2810   // Max Mode is realy an intersection of the QueryMode command to all\r
2811   // devices. So we must copy the QueryMode of the first device to\r
2812   // QueryData.\r
2813   //\r
2814   ZeroMem (\r
2815     Private->TextOutQueryData,\r
2816     Private->TextOutQueryDataCount * sizeof (TEXT_OUT_SPLITTER_QUERY_DATA)\r
2817     );\r
2818 \r
2819   FreePool (Private->TextOutModeMap);\r
2820   Private->TextOutModeMap = NULL;\r
2821   TextOutList             = Private->TextOutList;\r
2822 \r
2823   //\r
2824   // Add the first TextOut to the QueryData array and ModeMap table\r
2825   //\r
2826   Status = ConSplitterAddOutputMode (Private, TextOutList->TextOut);\r
2827 \r
2828   //\r
2829   // Now add one by one\r
2830   //\r
2831   Index = 1;\r
2832   Private->CurrentNumberOfConsoles = 1;\r
2833   TextOutList++;\r
2834   while ((UINTN) Index < CurrentNumOfConsoles) {\r
2835     ConSplitterSyncOutputMode (Private, TextOutList->TextOut);\r
2836     Index++;\r
2837     Private->CurrentNumberOfConsoles++;\r
2838     TextOutList++;\r
2839   }\r
2840 \r
2841   ConSplitterGetIntersectionBetweenConOutAndStrErr ();\r
2842 \r
2843   return Status;\r
2844 }\r
2845 //\r
2846 // ConSplitter TextIn member functions\r
2847 //\r
2848 EFI_STATUS\r
2849 EFIAPI\r
2850 ConSplitterTextInReset (\r
2851   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,\r
2852   IN  BOOLEAN                         ExtendedVerification\r
2853   )\r
2854 /*++\r
2855 \r
2856   Routine Description:\r
2857     Reset the input device and optionaly run diagnostics\r
2858 \r
2859   Arguments:\r
2860     This                 - Protocol instance pointer.\r
2861     ExtendedVerification - Driver may perform diagnostics on reset.\r
2862 \r
2863   Returns:\r
2864     EFI_SUCCESS           - The device was reset.\r
2865     EFI_DEVICE_ERROR      - The device is not functioning properly and could\r
2866                             not be reset.\r
2867 \r
2868 --*/\r
2869 {\r
2870   EFI_STATUS                    Status;\r
2871   EFI_STATUS                    ReturnStatus;\r
2872   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;\r
2873   UINTN                         Index;\r
2874 \r
2875   Private                       = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
2876 \r
2877   Private->KeyEventSignalState  = FALSE;\r
2878 \r
2879   //\r
2880   // return the worst status met\r
2881   //\r
2882   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {\r
2883     Status = Private->TextInList[Index]->Reset (\r
2884                                           Private->TextInList[Index],\r
2885                                           ExtendedVerification\r
2886                                           );\r
2887     if (EFI_ERROR (Status)) {\r
2888       ReturnStatus = Status;\r
2889     }\r
2890   }\r
2891 \r
2892   return ReturnStatus;\r
2893 }\r
2894 \r
2895 EFI_STATUS\r
2896 EFIAPI\r
2897 ConSplitterTextInPrivateReadKeyStroke (\r
2898   IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,\r
2899   OUT EFI_INPUT_KEY                   *Key\r
2900   )\r
2901 /*++\r
2902 \r
2903   Routine Description:\r
2904     Reads the next keystroke from the input device. The WaitForKey Event can\r
2905     be used to test for existance of a keystroke via WaitForEvent () call.\r
2906 \r
2907   Arguments:\r
2908     This   - Protocol instance pointer.\r
2909     Key    - Driver may perform diagnostics on reset.\r
2910 \r
2911   Returns:\r
2912     EFI_SUCCESS       - The keystroke information was returned.\r
2913     EFI_NOT_READY     - There was no keystroke data availiable.\r
2914     EFI_DEVICE_ERROR  - The keydtroke information was not returned due to\r
2915                         hardware errors.\r
2916 \r
2917 --*/\r
2918 {\r
2919   EFI_STATUS    Status;\r
2920   UINTN         Index;\r
2921   EFI_INPUT_KEY CurrentKey;\r
2922 \r
2923   Key->UnicodeChar  = 0;\r
2924   Key->ScanCode     = SCAN_NULL;\r
2925 \r
2926   //\r
2927   // if no physical console input device exists, return EFI_NOT_READY;\r
2928   // if any physical console input device has key input,\r
2929   // return the key and EFI_SUCCESS.\r
2930   //\r
2931   for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {\r
2932     Status = Private->TextInList[Index]->ReadKeyStroke (\r
2933                                           Private->TextInList[Index],\r
2934                                           &CurrentKey\r
2935                                           );\r
2936     if (!EFI_ERROR (Status)) {\r
2937       *Key = CurrentKey;\r
2938       return Status;\r
2939     }\r
2940   }\r
2941 \r
2942   return EFI_NOT_READY;\r
2943 }\r
2944 \r
2945 BOOLEAN\r
2946 ConSpliterConssoleControlStdInLocked (\r
2947   VOID\r
2948   )\r
2949 /*++\r
2950 \r
2951 Routine Description:\r
2952   Return TRUE if StdIn is locked. The ConIn device on the virtual handle is\r
2953   the only device locked.\r
2954 \r
2955 Arguments:\r
2956   NONE\r
2957 \r
2958 Returns:\r
2959   TRUE  - StdIn locked\r
2960   FALSE - StdIn working normally\r
2961 \r
2962 --*/\r
2963 {\r
2964   return mConIn.PasswordEnabled;\r
2965 }\r
2966 \r
2967 VOID\r
2968 EFIAPI\r
2969 ConSpliterConsoleControlLockStdInEvent (\r
2970   IN  EFI_EVENT                       Event,\r
2971   IN  VOID                            *Context\r
2972   )\r
2973 /*++\r
2974 \r
2975 Routine Description:\r
2976   This timer event will fire when StdIn is locked. It will check the key\r
2977   sequence on StdIn to see if it matches the password. Any error in the\r
2978   password will cause the check to reset. As long a mConIn.PasswordEnabled is\r
2979   TRUE the StdIn splitter will not report any input.\r
2980 \r
2981 Arguments:\r
2982   (Standard EFI_EVENT_NOTIFY)\r
2983 \r
2984 Returns:\r
2985   None\r
2986 \r
2987 --*/\r
2988 {\r
2989   EFI_STATUS    Status;\r
2990   EFI_INPUT_KEY Key;\r
2991   CHAR16        BackSpaceString[2];\r
2992   CHAR16        SpaceString[2];\r
2993 \r
2994   do {\r
2995     Status = ConSplitterTextInPrivateReadKeyStroke (&mConIn, &Key);\r
2996     if (!EFI_ERROR (Status)) {\r
2997       //\r
2998       // if it's an ENTER, match password\r
2999       //\r
3000       if ((Key.UnicodeChar == CHAR_CARRIAGE_RETURN) && (Key.ScanCode == SCAN_NULL)) {\r
3001         mConIn.PwdAttempt[mConIn.PwdIndex] = CHAR_NULL;\r
3002         if (StrCmp (mConIn.Password, mConIn.PwdAttempt)) {\r
3003           //\r
3004           // Password not match\r
3005           //\r
3006           ConSplitterTextOutOutputString (&mConOut.TextOut, (CHAR16 *) L"\n\rPassword not correct\n\r");\r
3007           mConIn.PwdIndex = 0;\r
3008         } else {\r
3009           //\r
3010           // Key matches password sequence\r
3011           //\r
3012           gBS->SetTimer (mConIn.LockEvent, TimerPeriodic, 0);\r
3013           mConIn.PasswordEnabled  = FALSE;\r
3014           Status                  = EFI_NOT_READY;\r
3015         }\r
3016       } else if ((Key.UnicodeChar == CHAR_BACKSPACE) && (Key.ScanCode == SCAN_NULL)) {\r
3017         //\r
3018         // BackSpace met\r
3019         //\r
3020         if (mConIn.PwdIndex > 0) {\r
3021           BackSpaceString[0]  = CHAR_BACKSPACE;\r
3022           BackSpaceString[1]  = 0;\r
3023 \r
3024           SpaceString[0]      = ' ';\r
3025           SpaceString[1]      = 0;\r
3026 \r
3027           ConSplitterTextOutOutputString (&mConOut.TextOut, BackSpaceString);\r
3028           ConSplitterTextOutOutputString (&mConOut.TextOut, SpaceString);\r
3029           ConSplitterTextOutOutputString (&mConOut.TextOut, BackSpaceString);\r
3030 \r
3031           mConIn.PwdIndex--;\r
3032         }\r
3033       } else if ((Key.ScanCode == SCAN_NULL) && (Key.UnicodeChar >= 32)) {\r
3034         //\r
3035         // If it's not an ENTER, neigher a function key, nor a CTRL-X or ALT-X, record the input\r
3036         //\r
3037         if (mConIn.PwdIndex < (MAX_STD_IN_PASSWORD - 1)) {\r
3038           if (mConIn.PwdIndex == 0) {\r
3039             ConSplitterTextOutOutputString (&mConOut.TextOut, (CHAR16 *) L"\n\r");\r
3040           }\r
3041 \r
3042           ConSplitterTextOutOutputString (&mConOut.TextOut, (CHAR16 *) L"*");\r
3043           mConIn.PwdAttempt[mConIn.PwdIndex] = Key.UnicodeChar;\r
3044           mConIn.PwdIndex++;\r
3045         }\r
3046       }\r
3047     }\r
3048   } while (!EFI_ERROR (Status));\r
3049 }\r
3050 \r
3051 EFI_STATUS\r
3052 EFIAPI\r
3053 ConSpliterConsoleControlLockStdIn (\r
3054   IN  EFI_CONSOLE_CONTROL_PROTOCOL    *This,\r
3055   IN  CHAR16                          *Password\r
3056   )\r
3057 /*++\r
3058 \r
3059 Routine Description:\r
3060   If Password is NULL unlock the password state variable and set the event\r
3061   timer. If the Password is too big return an error. If the Password is valid\r
3062   Copy the Password and enable state variable and then arm the periodic timer\r
3063 \r
3064 Arguments:\r
3065 \r
3066 Returns:\r
3067   EFI_SUCCESS           - Lock the StdIn device\r
3068   EFI_INVALID_PARAMETER - Password is NULL\r
3069   EFI_OUT_OF_RESOURCES  - Buffer allocation to store the password fails\r
3070 \r
3071 --*/\r
3072 {\r
3073   if (Password == NULL) {\r
3074     return EFI_INVALID_PARAMETER;\r
3075   }\r
3076 \r
3077   if (StrLen (Password) >= MAX_STD_IN_PASSWORD) {\r
3078     //\r
3079     // Currently have a max password size\r
3080     //\r
3081     return EFI_OUT_OF_RESOURCES;\r
3082   }\r
3083   //\r
3084   // Save the password, initialize state variables and arm event timer\r
3085   //\r
3086   StrCpy (mConIn.Password, Password);\r
3087   mConIn.PasswordEnabled  = TRUE;\r
3088   mConIn.PwdIndex         = 0;\r
3089   gBS->SetTimer (mConIn.LockEvent, TimerPeriodic, (10000 * 25));\r
3090 \r
3091   return EFI_SUCCESS;\r
3092 }\r
3093 \r
3094 EFI_STATUS\r
3095 EFIAPI\r
3096 ConSplitterTextInReadKeyStroke (\r
3097   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,\r
3098   OUT EFI_INPUT_KEY                   *Key\r
3099   )\r
3100 /*++\r
3101 \r
3102   Routine Description:\r
3103     Reads the next keystroke from the input device. The WaitForKey Event can\r
3104     be used to test for existance of a keystroke via WaitForEvent () call.\r
3105     If the ConIn is password locked make it look like no keystroke is availible\r
3106 \r
3107   Arguments:\r
3108     This   - Protocol instance pointer.\r
3109     Key    - Driver may perform diagnostics on reset.\r
3110 \r
3111   Returns:\r
3112     EFI_SUCCESS       - The keystroke information was returned.\r
3113     EFI_NOT_READY     - There was no keystroke data availiable.\r
3114     EFI_DEVICE_ERROR  - The keydtroke information was not returned due to\r
3115                         hardware errors.\r
3116 \r
3117 --*/\r
3118 {\r
3119   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;\r
3120 \r
3121   Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
3122   if (Private->PasswordEnabled) {\r
3123     //\r
3124     // If StdIn Locked return not ready\r
3125     //\r
3126     return EFI_NOT_READY;\r
3127   }\r
3128 \r
3129   Private->KeyEventSignalState = FALSE;\r
3130 \r
3131   return ConSplitterTextInPrivateReadKeyStroke (Private, Key);\r
3132 }\r
3133 \r
3134 VOID\r
3135 EFIAPI\r
3136 ConSplitterTextInWaitForKey (\r
3137   IN  EFI_EVENT                       Event,\r
3138   IN  VOID                            *Context\r
3139   )\r
3140 /*++\r
3141 \r
3142 Routine Description:\r
3143   This event agregates all the events of the ConIn devices in the spliter.\r
3144   If the ConIn is password locked then return.\r
3145   If any events of physical ConIn devices are signaled, signal the ConIn\r
3146   spliter event. This will cause the calling code to call\r
3147   ConSplitterTextInReadKeyStroke ().\r
3148 \r
3149 Arguments:\r
3150   Event   - The Event assoicated with callback.\r
3151   Context - Context registered when Event was created.\r
3152 \r
3153 Returns:\r
3154   None\r
3155 \r
3156 --*/\r
3157 {\r
3158   EFI_STATUS                    Status;\r
3159   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;\r
3160   UINTN                         Index;\r
3161 \r
3162   Private = (TEXT_IN_SPLITTER_PRIVATE_DATA *) Context;\r
3163   if (Private->PasswordEnabled) {\r
3164     //\r
3165     // If StdIn Locked return not ready\r
3166     //\r
3167     return ;\r
3168   }\r
3169 \r
3170   //\r
3171   // if KeyEventSignalState is flagged before, and not cleared by Reset() or ReadKeyStroke()\r
3172   //\r
3173   if (Private->KeyEventSignalState) {\r
3174     gBS->SignalEvent (Event);\r
3175     return ;\r
3176   }\r
3177   //\r
3178   // if any physical console input device has key input, signal the event.\r
3179   //\r
3180   for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {\r
3181     Status = gBS->CheckEvent (Private->TextInList[Index]->WaitForKey);\r
3182     if (!EFI_ERROR (Status)) {\r
3183       gBS->SignalEvent (Event);\r
3184       Private->KeyEventSignalState = TRUE;\r
3185     }\r
3186   }\r
3187 }\r
3188 \r
3189 \r
3190 STATIC\r
3191 BOOLEAN\r
3192 IsKeyRegistered (\r
3193   IN EFI_KEY_DATA  *RegsiteredData,\r
3194   IN EFI_KEY_DATA  *InputData\r
3195   )\r
3196 /*++\r
3197 \r
3198 Routine Description:\r
3199 \r
3200 Arguments:\r
3201 \r
3202   RegsiteredData    - A pointer to a buffer that is filled in with the keystroke\r
3203                       state data for the key that was registered.\r
3204   InputData         - A pointer to a buffer that is filled in with the keystroke\r
3205                       state data for the key that was pressed.\r
3206 \r
3207 Returns:\r
3208   TRUE              - Key be pressed matches a registered key.\r
3209   FLASE             - Match failed.\r
3210 \r
3211 --*/\r
3212 {\r
3213   ASSERT (RegsiteredData != NULL && InputData != NULL);\r
3214 \r
3215   if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||\r
3216       (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {\r
3217     return FALSE;\r
3218   }\r
3219 \r
3220   //\r
3221   // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.\r
3222   //\r
3223   if (RegsiteredData->KeyState.KeyShiftState != 0 &&\r
3224       RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {\r
3225     return FALSE;\r
3226   }\r
3227   if (RegsiteredData->KeyState.KeyToggleState != 0 &&\r
3228       RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {\r
3229     return FALSE;\r
3230   }\r
3231 \r
3232   return TRUE;\r
3233 \r
3234 }\r
3235 \r
3236 //\r
3237 // Simple Text Input Ex protocol functions\r
3238 //\r
3239 \r
3240 EFI_STATUS\r
3241 EFIAPI\r
3242 ConSplitterTextInResetEx (\r
3243   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
3244   IN BOOLEAN                            ExtendedVerification\r
3245   )\r
3246 /*++\r
3247 \r
3248   Routine Description:\r
3249     Reset the input device and optionaly run diagnostics\r
3250 \r
3251   Arguments:\r
3252     This                 - Protocol instance pointer.\r
3253     ExtendedVerification - Driver may perform diagnostics on reset.\r
3254 \r
3255   Returns:\r