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