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