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