Clean codes per ECC for ConSplitterDxe module.
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Universal / Console / ConSplitterDxe / ConSplitterGraphics.c
1 /** @file\r
2   Support for ConsoleControl protocol. Support for Graphics output spliter.\r
3   Support for DevNull Console Out. This console uses memory buffers\r
4   to represnt the console. It allows a console to start very early and\r
5   when a new console is added it is synced up with the current console.\r
6 \r
7 Copyright (c) 2006 - 2008, Intel Corporation. <BR>\r
8 All rights reserved. This program and the accompanying materials\r
9 are licensed and made available under the terms and conditions of the BSD License\r
10 which accompanies this distribution.  The full text of the license may be found at\r
11 http://opensource.org/licenses/bsd-license.php\r
12 \r
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
15 \r
16 \r
17 **/\r
18 \r
19 \r
20 #include "ConSplitter.h"\r
21 \r
22 \r
23 STATIC CHAR16 mCrLfString[3] = { CHAR_CARRIAGE_RETURN, CHAR_LINEFEED, CHAR_NULL };\r
24 \r
25 \r
26 /**\r
27   Return the current video mode information. Also returns info about existence\r
28   of Graphics Output devices or UGA Draw devices in system, and if the Std In device is locked. All the\r
29   arguments are optional and only returned if a non NULL pointer is passed in.\r
30 \r
31   @param  This                    Protocol instance pointer.\r
32   @param  Mode                    Are we in text of grahics mode.\r
33   @param  GopExists               TRUE if GOP Spliter has found a GOP/UGA device\r
34   @param  StdInLocked             TRUE if StdIn device is keyboard locked\r
35 \r
36   @retval EFI_SUCCESS             Mode information returned.\r
37   @retval EFI_INVALID_PARAMETER   Invalid parameters.\r
38 \r
39 **/\r
40 EFI_STATUS\r
41 EFIAPI\r
42 ConSpliterConsoleControlGetMode (\r
43   IN  EFI_CONSOLE_CONTROL_PROTOCOL    *This,\r
44   OUT EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode,\r
45   OUT BOOLEAN                         *GopExists,\r
46   OUT BOOLEAN                         *StdInLocked\r
47   )\r
48 {\r
49   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;\r
50   UINTN                           Index;\r
51 \r
52   Private = CONSOLE_CONTROL_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
53 \r
54   if (Mode == NULL) {\r
55     return EFI_INVALID_PARAMETER;\r
56   }\r
57 \r
58   *Mode = Private->ConsoleOutputMode;\r
59 \r
60   if (GopExists != NULL) {\r
61     *GopExists = FALSE;\r
62     for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {\r
63       if ((Private->TextOutList[Index].GraphicsOutput != NULL) || (Private->TextOutList[Index].UgaDraw != NULL)) {\r
64         *GopExists = TRUE;\r
65         break;\r
66       }\r
67     }\r
68   }\r
69 \r
70   if (StdInLocked != NULL) {\r
71     *StdInLocked = ConSpliterConssoleControlStdInLocked ();\r
72   }\r
73 \r
74   return EFI_SUCCESS;\r
75 }\r
76 \r
77 \r
78 /**\r
79   Set the current mode to either text or graphics. Graphics is\r
80   for Quiet Boot.\r
81 \r
82   @param  This                    Protocol instance pointer.\r
83   @param  Mode                    Mode to set the\r
84 \r
85   @retval EFI_SUCCESS             Mode information returned.\r
86   @retval EFI_INVALID_PARAMETER   Invalid parameter.\r
87   @retval EFI_UNSUPPORTED         Operation unsupported.\r
88 \r
89 **/\r
90 EFI_STATUS\r
91 EFIAPI\r
92 ConSpliterConsoleControlSetMode (\r
93   IN  EFI_CONSOLE_CONTROL_PROTOCOL    *This,\r
94   IN  EFI_CONSOLE_CONTROL_SCREEN_MODE Mode\r
95   )\r
96 {\r
97   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;\r
98   UINTN                           Index;\r
99   TEXT_OUT_AND_GOP_DATA           *TextAndGop;\r
100   BOOLEAN                         Supported;\r
101 \r
102   Private = CONSOLE_CONTROL_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
103 \r
104   if (Mode >= EfiConsoleControlScreenMaxValue) {\r
105     return EFI_INVALID_PARAMETER;\r
106   }\r
107 \r
108   //\r
109   // Judge current mode with wanted mode at first.\r
110   //\r
111   if (Private->ConsoleOutputMode == Mode) {\r
112     return EFI_SUCCESS;\r
113   }\r
114 \r
115   Supported   = FALSE;\r
116   TextAndGop  = &Private->TextOutList[0];\r
117   for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++, TextAndGop++) {\r
118     if ((TextAndGop->GraphicsOutput != NULL) || (TextAndGop->UgaDraw != NULL)) {\r
119       Supported = TRUE;\r
120       break;\r
121     }\r
122   }\r
123 \r
124   if ((!Supported) && (Mode == EfiConsoleControlScreenGraphics)) {\r
125     return EFI_UNSUPPORTED;\r
126   }\r
127 \r
128   Private->ConsoleOutputMode  = Mode;\r
129 \r
130   TextAndGop = &Private->TextOutList[0];\r
131   for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++, TextAndGop++) {\r
132 \r
133     TextAndGop->TextOutEnabled = TRUE;\r
134     //\r
135     // If we are going into Graphics mode disable ConOut to any UGA device\r
136     //\r
137     if ((Mode == EfiConsoleControlScreenGraphics) &&((TextAndGop->GraphicsOutput != NULL) || (TextAndGop->UgaDraw != NULL))) {\r
138       TextAndGop->TextOutEnabled = FALSE;\r
139       if (FeaturePcdGet (PcdConOutGopSupport)) {\r
140         DevNullGopSync (Private, TextAndGop->GraphicsOutput, TextAndGop->UgaDraw);\r
141       } else if (FeaturePcdGet (PcdConOutUgaSupport)) {\r
142         DevNullUgaSync (Private, TextAndGop->GraphicsOutput, TextAndGop->UgaDraw);\r
143       }\r
144     }\r
145   }\r
146   if (Mode == EfiConsoleControlScreenText) {\r
147     DevNullSyncStdOut (Private);\r
148   }\r
149   return EFI_SUCCESS;\r
150 }\r
151 \r
152 \r
153 /**\r
154   Return the current video mode information.\r
155 \r
156   @param  This                    Protocol instance pointer.\r
157   @param  ModeNumber              The mode number to return information on.\r
158   @param  SizeOfInfo              A pointer to the size, in bytes, of the Info\r
159                                   buffer.\r
160   @param  Info                    Caller allocated buffer that returns information\r
161                                   about ModeNumber.\r
162 \r
163   @retval EFI_SUCCESS             Mode information returned.\r
164   @retval EFI_BUFFER_TOO_SMALL    The Info buffer was too small.\r
165   @retval EFI_DEVICE_ERROR        A hardware error occurred trying to retrieve the\r
166                                   video mode.\r
167   @retval EFI_NOT_STARTED         Video display is not initialized. Call SetMode ()\r
168   @retval EFI_INVALID_PARAMETER   One of the input args was NULL.\r
169 \r
170 **/\r
171 EFI_STATUS\r
172 EFIAPI\r
173 ConSpliterGraphicsOutputQueryMode (\r
174   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL          *This,\r
175   IN  UINT32                                ModeNumber,\r
176   OUT UINTN                                 *SizeOfInfo,\r
177   OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  **Info\r
178   )\r
179 {\r
180   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;\r
181 \r
182   if (This == NULL || Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) {\r
183     return EFI_INVALID_PARAMETER;\r
184   }\r
185 \r
186   //\r
187   // retrieve private data\r
188   //\r
189   Private = GRAPHICS_OUTPUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
190 \r
191   if (Private->HardwareNeedsStarting) {\r
192     return EFI_NOT_STARTED;\r
193   }\r
194 \r
195   *Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));\r
196 \r
197   if (*Info == NULL) {\r
198     return EFI_OUT_OF_RESOURCES;\r
199   }\r
200 \r
201   *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);\r
202 \r
203   CopyMem (*Info, &Private->GraphicsOutputModeBuffer[ModeNumber], *SizeOfInfo);\r
204 \r
205   return EFI_SUCCESS;\r
206 }\r
207 \r
208 \r
209 /**\r
210   Graphics output protocol interface to set video mode\r
211 \r
212   @param  This                    Protocol instance pointer.\r
213   @param  ModeNumber              The mode number to be set.\r
214 \r
215   @retval EFI_SUCCESS             Graphics mode was changed.\r
216   @retval EFI_DEVICE_ERROR        The device had an error and could not complete\r
217                                   the request.\r
218   @retval EFI_UNSUPPORTED         ModeNumber is not supported by this device.\r
219 \r
220 **/\r
221 EFI_STATUS\r
222 EFIAPI\r
223 ConSpliterGraphicsOutputSetMode (\r
224   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL * This,\r
225   IN  UINT32                       ModeNumber\r
226   )\r
227 {\r
228   EFI_STATUS                             Status;\r
229   TEXT_OUT_SPLITTER_PRIVATE_DATA         *Private;\r
230   UINTN                                  Index;\r
231   EFI_STATUS                             ReturnStatus;\r
232   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION   *Mode;\r
233   UINTN                                  Size;\r
234   EFI_GRAPHICS_OUTPUT_PROTOCOL           *GraphicsOutput;\r
235   UINTN                                  NumberIndex;\r
236   UINTN                                  SizeOfInfo;\r
237   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION   *Info;\r
238   EFI_UGA_DRAW_PROTOCOL                  *UgaDraw;\r
239 \r
240   if (ModeNumber >= This->Mode->MaxMode) {\r
241     return EFI_UNSUPPORTED;\r
242   }\r
243 \r
244   if (ModeNumber == This->Mode->Mode) {\r
245     return EFI_SUCCESS;\r
246   }\r
247 \r
248   Private = GRAPHICS_OUTPUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
249 \r
250   //\r
251   // GopDevNullSetMode ()\r
252   //\r
253   ReturnStatus = EFI_SUCCESS;\r
254 \r
255   //\r
256   // Free the old version\r
257   //\r
258   if (Private->GraphicsOutputBlt != NULL) {\r
259     FreePool (Private->GraphicsOutputBlt);\r
260   }\r
261 \r
262   //\r
263   // Allocate the virtual Blt buffer\r
264   //\r
265   Mode = &Private->GraphicsOutputModeBuffer[ModeNumber];\r
266   Size = Mode->HorizontalResolution * Mode->VerticalResolution * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);\r
267   Private->GraphicsOutputBlt = AllocateZeroPool (Size);\r
268 \r
269   if (Private->GraphicsOutputBlt == NULL) {\r
270     return EFI_OUT_OF_RESOURCES;\r
271   }\r
272 \r
273   //\r
274   // return the worst status met\r
275   //\r
276   for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {\r
277     GraphicsOutput = Private->TextOutList[Index].GraphicsOutput;\r
278     if (GraphicsOutput != NULL) {\r
279       //\r
280       // Find corresponding ModeNumber of this GraphicsOutput instance\r
281       //\r
282       for (NumberIndex = 0; NumberIndex < GraphicsOutput->Mode->MaxMode; NumberIndex ++) {\r
283         Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) NumberIndex, &SizeOfInfo, &Info);\r
284         if (EFI_ERROR (Status)) {\r
285           return Status;\r
286         }\r
287         if ((Info->HorizontalResolution == Mode->HorizontalResolution) && (Info->VerticalResolution == Mode->VerticalResolution)) {\r
288           FreePool (Info);\r
289           break;\r
290         }\r
291         FreePool (Info);\r
292       }\r
293 \r
294       Status = GraphicsOutput->SetMode (GraphicsOutput, (UINT32) NumberIndex);\r
295       if (EFI_ERROR (Status)) {\r
296         ReturnStatus = Status;\r
297       }\r
298     }\r
299 \r
300     if (EFI_ERROR (ReturnStatus) && FeaturePcdGet (PcdUgaConsumeSupport)) {\r
301       UgaDraw = Private->TextOutList[Index].UgaDraw;\r
302       if (UgaDraw != NULL) {\r
303         Status = UgaDraw->SetMode (\r
304                             UgaDraw,\r
305                             Mode->HorizontalResolution,\r
306                             Mode->VerticalResolution,\r
307                             32,\r
308                             60\r
309                             );\r
310         if (EFI_ERROR (Status)) {\r
311           ReturnStatus = Status;\r
312         }\r
313       }\r
314     }\r
315   }\r
316 \r
317   This->Mode->Mode = ModeNumber;\r
318 \r
319   CopyMem (This->Mode->Info, &Private->GraphicsOutputModeBuffer[ModeNumber], This->Mode->SizeOfInfo);\r
320 \r
321   //\r
322   // Information is not enough here, so the following items remain unchanged:\r
323   //  GraphicsOutputMode->Info->Version, GraphicsOutputMode->Info->PixelFormat\r
324   //  GraphicsOutputMode->SizeOfInfo, GraphicsOutputMode->FrameBufferBase, GraphicsOutputMode->FrameBufferSize\r
325   // These items will be initialized/updated when a new GOP device is added into ConsoleSplitter.\r
326   //\r
327 \r
328   Private->HardwareNeedsStarting = FALSE;\r
329 \r
330   return ReturnStatus;\r
331 }\r
332 \r
333 EFI_STATUS\r
334 DevNullGraphicsOutputBlt (\r
335   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA                *Private,\r
336   IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL                 *BltBuffer, OPTIONAL\r
337   IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION             BltOperation,\r
338   IN  UINTN                                         SourceX,\r
339   IN  UINTN                                         SourceY,\r
340   IN  UINTN                                         DestinationX,\r
341   IN  UINTN                                         DestinationY,\r
342   IN  UINTN                                         Width,\r
343   IN  UINTN                                         Height,\r
344   IN  UINTN                                         Delta         OPTIONAL\r
345   )\r
346 {\r
347   UINTN                         SrcY;\r
348   BOOLEAN                       Forward;\r
349   UINTN                         Index;\r
350   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltPtr;\r
351   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *ScreenPtr;\r
352   UINTN                         HorizontalResolution;\r
353   UINTN                         VerticalResolution;\r
354 \r
355   if ((BltOperation < EfiBltVideoFill) || (BltOperation >= EfiGraphicsOutputBltOperationMax)) {\r
356     return EFI_INVALID_PARAMETER;\r
357   }\r
358 \r
359   if (Width == 0 || Height == 0) {\r
360     return EFI_INVALID_PARAMETER;\r
361   }\r
362 \r
363   if (Delta == 0) {\r
364     Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);\r
365   }\r
366 \r
367   HorizontalResolution  = Private->GraphicsOutput.Mode->Info->HorizontalResolution;\r
368   VerticalResolution    = Private->GraphicsOutput.Mode->Info->VerticalResolution;\r
369 \r
370   //\r
371   // We need to fill the Virtual Screen buffer with the blt data.\r
372   //\r
373   if (BltOperation == EfiBltVideoToBltBuffer) {\r
374     //\r
375     // Video to BltBuffer: Source is Video, destination is BltBuffer\r
376     //\r
377     if ((SourceY + Height) > VerticalResolution) {\r
378       return EFI_INVALID_PARAMETER;\r
379     }\r
380 \r
381     if ((SourceX + Width) > HorizontalResolution) {\r
382       return EFI_INVALID_PARAMETER;\r
383     }\r
384 \r
385     BltPtr    = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + DestinationY * Delta + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
386     ScreenPtr = &Private->GraphicsOutputBlt[SourceY * HorizontalResolution + SourceX];\r
387     while (Height > 0) {\r
388       CopyMem (BltPtr, ScreenPtr, Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
389       BltPtr = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltPtr + Delta);\r
390       ScreenPtr += HorizontalResolution;\r
391       Height--;\r
392     }\r
393   } else {\r
394     //\r
395     // BltBuffer to Video: Source is BltBuffer, destination is Video\r
396     //\r
397     if (DestinationY + Height > VerticalResolution) {\r
398       return EFI_INVALID_PARAMETER;\r
399     }\r
400 \r
401     if (DestinationX + Width > HorizontalResolution) {\r
402       return EFI_INVALID_PARAMETER;\r
403     }\r
404 \r
405     if ((BltOperation == EfiBltVideoToVideo) && (DestinationY > SourceY)) {\r
406       //\r
407       // Copy backwards, only care the Video to Video Blt\r
408       //\r
409       ScreenPtr = &Private->GraphicsOutputBlt[(DestinationY + Height - 1) * HorizontalResolution + DestinationX];\r
410       SrcY      = SourceY + Height - 1;\r
411       Forward   = FALSE;\r
412     } else {\r
413       //\r
414       // Copy forwards, for other cases\r
415       //\r
416       ScreenPtr = &Private->GraphicsOutputBlt[DestinationY * HorizontalResolution + DestinationX];\r
417       SrcY      = SourceY;\r
418       Forward   = TRUE;\r
419     }\r
420 \r
421     while (Height != 0) {\r
422       if (BltOperation == EfiBltVideoFill) {\r
423         for (Index = 0; Index < Width; Index++) {\r
424           ScreenPtr[Index] = *BltBuffer;\r
425         }\r
426       } else {\r
427         if (BltOperation == EfiBltBufferToVideo) {\r
428           BltPtr = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + SrcY * Delta + SourceX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
429         } else {\r
430           BltPtr = &Private->GraphicsOutputBlt[SrcY * HorizontalResolution + SourceX];\r
431         }\r
432 \r
433         CopyMem (ScreenPtr, BltPtr, Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
434       }\r
435 \r
436       if (Forward) {\r
437         ScreenPtr += HorizontalResolution;\r
438         SrcY ++;\r
439       } else {\r
440         ScreenPtr -= HorizontalResolution;\r
441         SrcY --;\r
442       }\r
443       Height--;\r
444     }\r
445   }\r
446 \r
447   return EFI_SUCCESS;\r
448 }\r
449 \r
450 \r
451 /**\r
452   The following table defines actions for BltOperations.\r
453 \r
454   EfiBltVideoFill - Write data from the  BltBuffer pixel (SourceX, SourceY)\r
455   directly to every pixel of the video display rectangle\r
456   (DestinationX, DestinationY)\r
457   (DestinationX + Width, DestinationY + Height).\r
458   Only one pixel will be used from the BltBuffer. Delta is NOT used.\r
459   EfiBltVideoToBltBuffer - Read data from the video display rectangle\r
460   (SourceX, SourceY) (SourceX + Width, SourceY + Height) and place it in\r
461   the BltBuffer rectangle (DestinationX, DestinationY )\r
462   (DestinationX + Width, DestinationY + Height). If DestinationX or\r
463   DestinationY is not zero then Delta must be set to the length in bytes\r
464   of a row in the BltBuffer.\r
465   EfiBltBufferToVideo - Write data from the  BltBuffer rectangle\r
466   (SourceX, SourceY) (SourceX + Width, SourceY + Height) directly to the\r
467   video display rectangle (DestinationX, DestinationY)\r
468   (DestinationX + Width, DestinationY + Height). If SourceX or SourceY is\r
469   not zero then Delta must be set to the length in bytes of a row in the\r
470   BltBuffer.\r
471   EfiBltVideoToVideo - Copy from the video display rectangle\r
472   (SourceX, SourceY) (SourceX + Width, SourceY + Height) .\r
473   to the video display rectangle (DestinationX, DestinationY)\r
474   (DestinationX + Width, DestinationY + Height).\r
475   The BltBuffer and Delta  are not used in this mode.\r
476 \r
477   @param  This                    Protocol instance pointer.\r
478   @param  BltBuffer               Buffer containing data to blit into video buffer.\r
479                                   This buffer has a size of\r
480                                   Width*Height*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)\r
481   @param  BltOperation            Operation to perform on BlitBuffer and video\r
482                                   memory\r
483   @param  SourceX                 X coordinate of source for the BltBuffer.\r
484   @param  SourceY                 Y coordinate of source for the BltBuffer.\r
485   @param  DestinationX            X coordinate of destination for the BltBuffer.\r
486   @param  DestinationY            Y coordinate of destination for the BltBuffer.\r
487   @param  Width                   Width of rectangle in BltBuffer in pixels.\r
488   @param  Height                  Hight of rectangle in BltBuffer in pixels. Delta\r
489                                          -\r
490 \r
491   @retval EFI_SUCCESS             The Blt operation completed.\r
492   @retval EFI_INVALID_PARAMETER   BltOperation is not valid.\r
493   @retval EFI_DEVICE_ERROR        A hardware error occured writting to the video\r
494                                   buffer.\r
495 \r
496 **/\r
497 EFI_STATUS\r
498 EFIAPI\r
499 ConSpliterGraphicsOutputBlt (\r
500   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL                  *This,\r
501   IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL                 *BltBuffer, OPTIONAL\r
502   IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION             BltOperation,\r
503   IN  UINTN                                         SourceX,\r
504   IN  UINTN                                         SourceY,\r
505   IN  UINTN                                         DestinationX,\r
506   IN  UINTN                                         DestinationY,\r
507   IN  UINTN                                         Width,\r
508   IN  UINTN                                         Height,\r
509   IN  UINTN                                         Delta         OPTIONAL\r
510   )\r
511 {\r
512   EFI_STATUS                      Status;\r
513   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;\r
514   UINTN                           Index;\r
515   EFI_STATUS                      ReturnStatus;\r
516   EFI_GRAPHICS_OUTPUT_PROTOCOL    *GraphicsOutput;\r
517   EFI_UGA_DRAW_PROTOCOL           *UgaDraw;\r
518 \r
519   Private = GRAPHICS_OUTPUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
520 \r
521   //\r
522   // Sync up DevNull GOP device\r
523   //\r
524   ReturnStatus = DevNullGraphicsOutputBlt (\r
525                   Private,\r
526                   BltBuffer,\r
527                   BltOperation,\r
528                   SourceX,\r
529                   SourceY,\r
530                   DestinationX,\r
531                   DestinationY,\r
532                   Width,\r
533                   Height,\r
534                   Delta\r
535                   );\r
536 \r
537   if (Private->ConsoleOutputMode != EfiConsoleControlScreenGraphics) {\r
538     return ReturnStatus;\r
539   }\r
540   //\r
541   // return the worst status met\r
542   //\r
543   for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {\r
544     GraphicsOutput = Private->TextOutList[Index].GraphicsOutput;\r
545     if (GraphicsOutput != NULL) {\r
546       Status = GraphicsOutput->Blt (\r
547                               GraphicsOutput,\r
548                               BltBuffer,\r
549                               BltOperation,\r
550                               SourceX,\r
551                               SourceY,\r
552                               DestinationX,\r
553                               DestinationY,\r
554                               Width,\r
555                               Height,\r
556                               Delta\r
557                               );\r
558       if (EFI_ERROR (Status)) {\r
559         ReturnStatus = Status;\r
560       } else if (BltOperation == EfiBltVideoToBltBuffer) {\r
561         //\r
562         // Only need to read the data into buffer one time\r
563         //\r
564         return EFI_SUCCESS;\r
565       }\r
566     }\r
567 \r
568     UgaDraw = Private->TextOutList[Index].UgaDraw;\r
569     if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {\r
570       Status = UgaDraw->Blt (\r
571                               UgaDraw,\r
572                               (EFI_UGA_PIXEL *) BltBuffer,\r
573                               (EFI_UGA_BLT_OPERATION) BltOperation,\r
574                               SourceX,\r
575                               SourceY,\r
576                               DestinationX,\r
577                               DestinationY,\r
578                               Width,\r
579                               Height,\r
580                               Delta\r
581                               );\r
582       if (EFI_ERROR (Status)) {\r
583         ReturnStatus = Status;\r
584       } else if (BltOperation == EfiBltVideoToBltBuffer) {\r
585         //\r
586         // Only need to read the data into buffer one time\r
587         //\r
588         return EFI_SUCCESS;\r
589       }\r
590     }\r
591   }\r
592 \r
593   return ReturnStatus;\r
594 }\r
595 \r
596 EFI_STATUS\r
597 DevNullGopSync (\r
598   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private,\r
599   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL    *GraphicsOutput,\r
600   IN  EFI_UGA_DRAW_PROTOCOL           *UgaDraw\r
601   )\r
602 {\r
603   if (GraphicsOutput != NULL) {\r
604     return GraphicsOutput->Blt (\r
605                       GraphicsOutput,\r
606                       Private->GraphicsOutputBlt,\r
607                       EfiBltBufferToVideo,\r
608                       0,\r
609                       0,\r
610                       0,\r
611                       0,\r
612                       Private->GraphicsOutput.Mode->Info->HorizontalResolution,\r
613                       Private->GraphicsOutput.Mode->Info->VerticalResolution,\r
614                       0\r
615                       );\r
616   } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {\r
617     return UgaDraw->Blt (\r
618                       UgaDraw,\r
619                       (EFI_UGA_PIXEL *) Private->GraphicsOutputBlt,\r
620                       EfiUgaBltBufferToVideo,\r
621                       0,\r
622                       0,\r
623                       0,\r
624                       0,\r
625                       Private->GraphicsOutput.Mode->Info->HorizontalResolution,\r
626                       Private->GraphicsOutput.Mode->Info->VerticalResolution,\r
627                       0\r
628                       );\r
629   } else {\r
630     return EFI_UNSUPPORTED;\r
631   }\r
632 }\r
633 \r
634 \r
635 /**\r
636   Return the current video mode information.\r
637 \r
638   @param  This                    Protocol instance pointer.\r
639   @param  HorizontalResolution    Current video horizontal resolution in pixels\r
640   @param  VerticalResolution      Current video vertical resolution in pixels\r
641   @param  ColorDepth              Current video color depth in bits per pixel\r
642   @param  RefreshRate             Current video refresh rate in Hz.\r
643 \r
644   @retval EFI_SUCCESS             Mode information returned.\r
645   @retval EFI_NOT_STARTED         Video display is not initialized. Call SetMode ()\r
646   @retval EFI_INVALID_PARAMETER   One of the input args was NULL.\r
647 \r
648 **/\r
649 EFI_STATUS\r
650 EFIAPI\r
651 ConSpliterUgaDrawGetMode (\r
652   IN  EFI_UGA_DRAW_PROTOCOL           *This,\r
653   OUT UINT32                          *HorizontalResolution,\r
654   OUT UINT32                          *VerticalResolution,\r
655   OUT UINT32                          *ColorDepth,\r
656   OUT UINT32                          *RefreshRate\r
657   )\r
658 {\r
659   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;\r
660 \r
661   if ((HorizontalResolution == NULL) ||\r
662           (VerticalResolution   == NULL) ||\r
663           (RefreshRate          == NULL) ||\r
664           (ColorDepth           == NULL)) {\r
665     return EFI_INVALID_PARAMETER;\r
666   }\r
667   //\r
668   // retrieve private data\r
669   //\r
670   Private               = UGA_DRAW_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
671 \r
672   *HorizontalResolution = Private->UgaHorizontalResolution;\r
673   *VerticalResolution   = Private->UgaVerticalResolution;\r
674   *ColorDepth           = Private->UgaColorDepth;\r
675   *RefreshRate          = Private->UgaRefreshRate;\r
676 \r
677   return EFI_SUCCESS;\r
678 }\r
679 \r
680 \r
681 /**\r
682   Return the current video mode information.\r
683 \r
684   @param  This                    Protocol instance pointer.\r
685   @param  HorizontalResolution    Current video horizontal resolution in pixels\r
686   @param  VerticalResolution      Current video vertical resolution in pixels\r
687   @param  ColorDepth              Current video color depth in bits per pixel\r
688   @param  RefreshRate             Current video refresh rate in Hz.\r
689 \r
690   @retval EFI_SUCCESS             Mode information returned.\r
691   @retval EFI_NOT_STARTED         Video display is not initialized. Call SetMode ()\r
692   @retval EFI_OUT_OF_RESOURCES    Out of resources.\r
693 \r
694 **/\r
695 EFI_STATUS\r
696 EFIAPI\r
697 ConSpliterUgaDrawSetMode (\r
698   IN  EFI_UGA_DRAW_PROTOCOL           *This,\r
699   IN UINT32                           HorizontalResolution,\r
700   IN UINT32                           VerticalResolution,\r
701   IN UINT32                           ColorDepth,\r
702   IN UINT32                           RefreshRate\r
703   )\r
704 {\r
705   EFI_STATUS                             Status;\r
706   TEXT_OUT_SPLITTER_PRIVATE_DATA         *Private;\r
707   UINTN                                  Index;\r
708   EFI_STATUS                             ReturnStatus;\r
709   UINTN                                  Size;\r
710   EFI_GRAPHICS_OUTPUT_PROTOCOL           *GraphicsOutput;\r
711   UINTN                                  NumberIndex;\r
712   UINTN                                  SizeOfInfo;\r
713   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION   *Info;\r
714   EFI_UGA_DRAW_PROTOCOL                  *UgaDraw;\r
715 \r
716   Private = UGA_DRAW_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
717 \r
718   //\r
719   // UgaDevNullSetMode ()\r
720   //\r
721   ReturnStatus = EFI_SUCCESS;\r
722 \r
723   //\r
724   // Free the old version\r
725   //\r
726   if (Private->UgaBlt != NULL) {\r
727     FreePool (Private->UgaBlt);\r
728   }\r
729 \r
730   //\r
731   // Allocate the virtual Blt buffer\r
732   //\r
733   Size            = HorizontalResolution * VerticalResolution * sizeof (EFI_UGA_PIXEL);\r
734   Private->UgaBlt = AllocateZeroPool (Size);\r
735   if (Private->UgaBlt == NULL) {\r
736     return EFI_OUT_OF_RESOURCES;\r
737   }\r
738 \r
739   //\r
740   // Update the Mode data\r
741   //\r
742   Private->UgaHorizontalResolution  = HorizontalResolution;\r
743   Private->UgaVerticalResolution    = VerticalResolution;\r
744   Private->UgaColorDepth            = ColorDepth;\r
745   Private->UgaRefreshRate           = RefreshRate;\r
746 \r
747   if (Private->ConsoleOutputMode != EfiConsoleControlScreenGraphics) {\r
748     return ReturnStatus;\r
749   }\r
750   //\r
751   // return the worst status met\r
752   //\r
753   for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {\r
754 \r
755     ReturnStatus = EFI_UNSUPPORTED;\r
756 \r
757     if (FeaturePcdGet (PcdUgaConsumeSupport)) {\r
758       UgaDraw = Private->TextOutList[Index].UgaDraw;\r
759       if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {\r
760         Status = UgaDraw->SetMode (\r
761                             UgaDraw,\r
762                             HorizontalResolution,\r
763                             VerticalResolution,\r
764                             ColorDepth,\r
765                             RefreshRate\r
766                             );\r
767         if (EFI_ERROR (Status)) {\r
768           ReturnStatus = Status;\r
769         }\r
770       }\r
771     }\r
772 \r
773     if (EFI_ERROR (ReturnStatus)) {\r
774       GraphicsOutput = Private->TextOutList[Index].GraphicsOutput;\r
775       if (GraphicsOutput != NULL) {\r
776         //\r
777         // Find corresponding ModeNumber of this GraphicsOutput instance\r
778         //\r
779         for (NumberIndex = 0; NumberIndex < GraphicsOutput->Mode->MaxMode; NumberIndex ++) {\r
780           Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) NumberIndex, &SizeOfInfo, &Info);\r
781           if (EFI_ERROR (Status)) {\r
782             return Status;\r
783           }\r
784           if ((Info->HorizontalResolution == HorizontalResolution) && (Info->VerticalResolution == VerticalResolution)) {\r
785             FreePool (Info);\r
786             break;\r
787           }\r
788           FreePool (Info);\r
789         }\r
790 \r
791         Status = GraphicsOutput->SetMode (GraphicsOutput, (UINT32) NumberIndex);\r
792         if (EFI_ERROR (Status)) {\r
793           ReturnStatus = Status;\r
794         }\r
795       }\r
796     }\r
797   }\r
798 \r
799   return ReturnStatus;\r
800 }\r
801 \r
802 EFI_STATUS\r
803 DevNullUgaBlt (\r
804   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA                *Private,\r
805   IN  EFI_UGA_PIXEL                                 *BltBuffer, OPTIONAL\r
806   IN  EFI_UGA_BLT_OPERATION                         BltOperation,\r
807   IN  UINTN                                         SourceX,\r
808   IN  UINTN                                         SourceY,\r
809   IN  UINTN                                         DestinationX,\r
810   IN  UINTN                                         DestinationY,\r
811   IN  UINTN                                         Width,\r
812   IN  UINTN                                         Height,\r
813   IN  UINTN                                         Delta         OPTIONAL\r
814   )\r
815 {\r
816   UINTN         SrcY;\r
817   BOOLEAN       Forward;\r
818   UINTN         Index;\r
819   EFI_UGA_PIXEL *BltPtr;\r
820   EFI_UGA_PIXEL *ScreenPtr;\r
821   UINT32        HorizontalResolution;\r
822   UINT32        VerticalResolution;\r
823 \r
824   if ((BltOperation < 0) || (BltOperation >= EfiUgaBltMax)) {\r
825     return EFI_INVALID_PARAMETER;\r
826   }\r
827 \r
828   if (Width == 0 || Height == 0) {\r
829     return EFI_INVALID_PARAMETER;\r
830   }\r
831 \r
832   if (Delta == 0) {\r
833     Delta = Width * sizeof (EFI_UGA_PIXEL);\r
834   }\r
835 \r
836   HorizontalResolution  = Private->UgaHorizontalResolution;\r
837   VerticalResolution    = Private->UgaVerticalResolution;\r
838 \r
839   //\r
840   // We need to fill the Virtual Screen buffer with the blt data.\r
841   //\r
842   if (BltOperation == EfiUgaVideoToBltBuffer) {\r
843     //\r
844     // Video to BltBuffer: Source is Video, destination is BltBuffer\r
845     //\r
846     if ((SourceY + Height) > VerticalResolution) {\r
847       return EFI_INVALID_PARAMETER;\r
848     }\r
849 \r
850     if ((SourceX + Width) > HorizontalResolution) {\r
851       return EFI_INVALID_PARAMETER;\r
852     }\r
853 \r
854     BltPtr    = (EFI_UGA_PIXEL *) ((UINT8 *) BltBuffer + DestinationY * Delta + DestinationX * sizeof (EFI_UGA_PIXEL));\r
855     ScreenPtr = &Private->UgaBlt[SourceY * HorizontalResolution + SourceX];\r
856     while (Height > 0) {\r
857       CopyMem (BltPtr, ScreenPtr, Width * sizeof (EFI_UGA_PIXEL));\r
858       BltPtr = (EFI_UGA_PIXEL *) ((UINT8 *) BltPtr + Delta);\r
859       ScreenPtr += HorizontalResolution;\r
860       Height--;\r
861     }\r
862   } else {\r
863     //\r
864     // BltBuffer to Video: Source is BltBuffer, destination is Video\r
865     //\r
866     if (DestinationY + Height > VerticalResolution) {\r
867       return EFI_INVALID_PARAMETER;\r
868     }\r
869 \r
870     if (DestinationX + Width > HorizontalResolution) {\r
871       return EFI_INVALID_PARAMETER;\r
872     }\r
873 \r
874     if ((BltOperation == EfiUgaVideoToVideo) && (DestinationY > SourceY)) {\r
875       //\r
876       // Copy backwards, only care the Video to Video Blt\r
877       //\r
878       ScreenPtr = &Private->UgaBlt[(DestinationY + Height - 1) * HorizontalResolution + DestinationX];\r
879       SrcY      = SourceY + Height - 1;\r
880       Forward   = FALSE;\r
881     } else {\r
882       //\r
883       // Copy forwards, for other cases\r
884       //\r
885       ScreenPtr = &Private->UgaBlt[DestinationY * HorizontalResolution + DestinationX];\r
886       SrcY      = SourceY;\r
887       Forward   = TRUE;\r
888     }\r
889 \r
890     while (Height != 0) {\r
891       if (BltOperation == EfiUgaVideoFill) {\r
892         for (Index = 0; Index < Width; Index++) {\r
893           ScreenPtr[Index] = *BltBuffer;\r
894         }\r
895       } else {\r
896         if (BltOperation == EfiUgaBltBufferToVideo) {\r
897           BltPtr = (EFI_UGA_PIXEL *) ((UINT8 *) BltBuffer + SrcY * Delta + SourceX * sizeof (EFI_UGA_PIXEL));\r
898         } else {\r
899           BltPtr = &Private->UgaBlt[SrcY * HorizontalResolution + SourceX];\r
900         }\r
901 \r
902         CopyMem (ScreenPtr, BltPtr, Width * sizeof (EFI_UGA_PIXEL));\r
903       }\r
904 \r
905       if (Forward) {\r
906         ScreenPtr += HorizontalResolution;\r
907         SrcY ++;\r
908       } else {\r
909         ScreenPtr -= HorizontalResolution;\r
910         SrcY --;\r
911       }\r
912       Height--;\r
913     }\r
914   }\r
915 \r
916   return EFI_SUCCESS;\r
917 }\r
918 \r
919 \r
920 /**\r
921   The following table defines actions for BltOperations.\r
922 \r
923   EfiUgaVideoFill - Write data from the  BltBuffer pixel (SourceX, SourceY)\r
924   directly to every pixel of the video display rectangle\r
925   (DestinationX, DestinationY)\r
926   (DestinationX + Width, DestinationY + Height).\r
927   Only one pixel will be used from the BltBuffer. Delta is NOT used.\r
928   EfiUgaVideoToBltBuffer - Read data from the video display rectangle\r
929   (SourceX, SourceY) (SourceX + Width, SourceY + Height) and place it in\r
930   the BltBuffer rectangle (DestinationX, DestinationY )\r
931   (DestinationX + Width, DestinationY + Height). If DestinationX or\r
932   DestinationY is not zero then Delta must be set to the length in bytes\r
933   of a row in the BltBuffer.\r
934   EfiUgaBltBufferToVideo - Write data from the  BltBuffer rectangle\r
935   (SourceX, SourceY) (SourceX + Width, SourceY + Height) directly to the\r
936   video display rectangle (DestinationX, DestinationY)\r
937   (DestinationX + Width, DestinationY + Height). If SourceX or SourceY is\r
938   not zero then Delta must be set to the length in bytes of a row in the\r
939   BltBuffer.\r
940   EfiUgaVideoToVideo - Copy from the video display rectangle\r
941   (SourceX, SourceY) (SourceX + Width, SourceY + Height) .\r
942   to the video display rectangle (DestinationX, DestinationY)\r
943   (DestinationX + Width, DestinationY + Height).\r
944   The BltBuffer and Delta  are not used in this mode.\r
945 \r
946   @param  This                    Protocol instance pointer.\r
947   @param  BltBuffer               Buffer containing data to blit into video buffer.\r
948                                   This buffer has a size of\r
949                                   Width*Height*sizeof(EFI_UGA_PIXEL)\r
950   @param  BltOperation            Operation to perform on BlitBuffer and video\r
951                                   memory\r
952   @param  SourceX                 X coordinate of source for the BltBuffer.\r
953   @param  SourceY                 Y coordinate of source for the BltBuffer.\r
954   @param  DestinationX            X coordinate of destination for the BltBuffer.\r
955   @param  DestinationY            Y coordinate of destination for the BltBuffer.\r
956   @param  Width                   Width of rectangle in BltBuffer in pixels.\r
957   @param  Height                  Hight of rectangle in BltBuffer in pixels. Delta\r
958                                          -\r
959 \r
960   @retval EFI_SUCCESS             The Blt operation completed.\r
961   @retval EFI_INVALID_PARAMETER   BltOperation is not valid.\r
962   @retval EFI_DEVICE_ERROR        A hardware error occured writting to the video\r
963                                   buffer.\r
964 \r
965 **/\r
966 EFI_STATUS\r
967 EFIAPI\r
968 ConSpliterUgaDrawBlt (\r
969   IN  EFI_UGA_DRAW_PROTOCOL                         *This,\r
970   IN  EFI_UGA_PIXEL                                 *BltBuffer, OPTIONAL\r
971   IN  EFI_UGA_BLT_OPERATION                         BltOperation,\r
972   IN  UINTN                                         SourceX,\r
973   IN  UINTN                                         SourceY,\r
974   IN  UINTN                                         DestinationX,\r
975   IN  UINTN                                         DestinationY,\r
976   IN  UINTN                                         Width,\r
977   IN  UINTN                                         Height,\r
978   IN  UINTN                                         Delta         OPTIONAL\r
979   )\r
980 {\r
981   EFI_STATUS                      Status;\r
982   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;\r
983   UINTN                           Index;\r
984   EFI_STATUS                      ReturnStatus;\r
985   EFI_GRAPHICS_OUTPUT_PROTOCOL    *GraphicsOutput;\r
986 \r
987   Private = UGA_DRAW_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
988 \r
989   //\r
990   // Sync up DevNull UGA device\r
991   //\r
992   ReturnStatus = DevNullUgaBlt (\r
993                   Private,\r
994                   BltBuffer,\r
995                   BltOperation,\r
996                   SourceX,\r
997                   SourceY,\r
998                   DestinationX,\r
999                   DestinationY,\r
1000                   Width,\r
1001                   Height,\r
1002                   Delta\r
1003                   );\r
1004   if (Private->ConsoleOutputMode != EfiConsoleControlScreenGraphics) {\r
1005     return ReturnStatus;\r
1006   }\r
1007   //\r
1008   // return the worst status met\r
1009   //\r
1010   for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {\r
1011     GraphicsOutput = Private->TextOutList[Index].GraphicsOutput;\r
1012     if (GraphicsOutput != NULL) {\r
1013       Status = GraphicsOutput->Blt (\r
1014                               GraphicsOutput,\r
1015                               (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) BltBuffer,\r
1016                               (EFI_GRAPHICS_OUTPUT_BLT_OPERATION) BltOperation,\r
1017                               SourceX,\r
1018                               SourceY,\r
1019                               DestinationX,\r
1020                               DestinationY,\r
1021                               Width,\r
1022                               Height,\r
1023                               Delta\r
1024                               );\r
1025       if (EFI_ERROR (Status)) {\r
1026         ReturnStatus = Status;\r
1027       } else if (BltOperation == EfiBltVideoToBltBuffer) {\r
1028         //\r
1029         // Only need to read the data into buffer one time\r
1030         //\r
1031         return EFI_SUCCESS;\r
1032       }\r
1033     }\r
1034 \r
1035     if (Private->TextOutList[Index].UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {\r
1036       Status = Private->TextOutList[Index].UgaDraw->Blt (\r
1037                                                       Private->TextOutList[Index].UgaDraw,\r
1038                                                       BltBuffer,\r
1039                                                       BltOperation,\r
1040                                                       SourceX,\r
1041                                                       SourceY,\r
1042                                                       DestinationX,\r
1043                                                       DestinationY,\r
1044                                                       Width,\r
1045                                                       Height,\r
1046                                                       Delta\r
1047                                                       );\r
1048       if (EFI_ERROR (Status)) {\r
1049         ReturnStatus = Status;\r
1050       } else if (BltOperation == EfiUgaVideoToBltBuffer) {\r
1051         //\r
1052         // Only need to read the data into buffer one time\r
1053         //\r
1054         return EFI_SUCCESS;\r
1055       }\r
1056     }\r
1057   }\r
1058 \r
1059   return ReturnStatus;\r
1060 }\r
1061 \r
1062 EFI_STATUS\r
1063 DevNullUgaSync (\r
1064   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private,\r
1065   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL    *GraphicsOutput,\r
1066   IN  EFI_UGA_DRAW_PROTOCOL           *UgaDraw\r
1067   )\r
1068 {\r
1069   if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {\r
1070     return UgaDraw->Blt (\r
1071                       UgaDraw,\r
1072                       Private->UgaBlt,\r
1073                       EfiUgaBltBufferToVideo,\r
1074                       0,\r
1075                       0,\r
1076                       0,\r
1077                       0,\r
1078                       Private->UgaHorizontalResolution,\r
1079                       Private->UgaVerticalResolution,\r
1080                       Private->UgaHorizontalResolution * sizeof (EFI_UGA_PIXEL)\r
1081                       );\r
1082   } else if (GraphicsOutput != NULL) {\r
1083     return GraphicsOutput->Blt (\r
1084                       GraphicsOutput,\r
1085                       (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) Private->UgaBlt,\r
1086                       EfiBltBufferToVideo,\r
1087                       0,\r
1088                       0,\r
1089                       0,\r
1090                       0,\r
1091                       Private->UgaHorizontalResolution,\r
1092                       Private->UgaVerticalResolution,\r
1093                       0\r
1094                       );\r
1095   } else {\r
1096     return EFI_UNSUPPORTED;\r
1097   }\r
1098 }\r
1099 \r
1100 \r
1101 /**\r
1102   Write a Unicode string to the output device.\r
1103 \r
1104   @param  Private                 Pointer to the console output splitter's private\r
1105                                   data. It indicates the calling context.\r
1106   @param  WString                 The NULL-terminated Unicode string to be\r
1107                                   displayed on the output device(s). All output\r
1108                                   devices must also support the Unicode drawing\r
1109                                   defined in this file.\r
1110 \r
1111   @retval EFI_SUCCESS             The string was output to the device.\r
1112   @retval EFI_DEVICE_ERROR        The device reported an error while attempting to\r
1113                                   output the text.\r
1114   @retval EFI_UNSUPPORTED         The output device's mode is not currently in a\r
1115                                   defined text mode.\r
1116   @retval EFI_WARN_UNKNOWN_GLYPH  This warning code indicates that some of the\r
1117                                   characters in the Unicode string could not be\r
1118                                   rendered and were skipped.\r
1119 \r
1120 **/\r
1121 EFI_STATUS\r
1122 DevNullTextOutOutputString (\r
1123   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private,\r
1124   IN  CHAR16                          *WString\r
1125   )\r
1126 {\r
1127   UINTN                       SizeScreen;\r
1128   UINTN                       SizeAttribute;\r
1129   UINTN                       Index;\r
1130   EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;\r
1131   CHAR16                      *Screen;\r
1132   CHAR16                      *NullScreen;\r
1133   CHAR16                      InsertChar;\r
1134   CHAR16                      TempChar;\r
1135   CHAR16                      *PStr;\r
1136   INT32                       *Attribute;\r
1137   INT32                       *NullAttributes;\r
1138   INT32                       CurrentWidth;\r
1139   UINTN                       LastRow;\r
1140   UINTN                       MaxColumn;\r
1141 \r
1142   Mode            = &Private->TextOutMode;\r
1143   NullScreen      = Private->DevNullScreen;\r
1144   NullAttributes  = Private->DevNullAttributes;\r
1145   LastRow         = Private->DevNullRows - 1;\r
1146   MaxColumn       = Private->DevNullColumns;\r
1147 \r
1148   if (Mode->Attribute & EFI_WIDE_ATTRIBUTE) {\r
1149     CurrentWidth = 2;\r
1150   } else {\r
1151     CurrentWidth = 1;\r
1152   }\r
1153 \r
1154   while (*WString != L'\0') {\r
1155 \r
1156     if (*WString == CHAR_BACKSPACE) {\r
1157       //\r
1158       // If the cursor is at the left edge of the display, then move the cursor\r
1159       // one row up.\r
1160       //\r
1161       if (Mode->CursorColumn == 0 && Mode->CursorRow > 0) {\r
1162         Mode->CursorRow--;\r
1163         Mode->CursorColumn = (INT32) MaxColumn;\r
1164       }\r
1165 \r
1166       //\r
1167       // If the cursor is not at the left edge of the display,\r
1168       // then move the cursor left one column.\r
1169       //\r
1170       if (Mode->CursorColumn > 0) {\r
1171         Mode->CursorColumn--;\r
1172         if (Mode->CursorColumn > 0 &&\r
1173             NullAttributes[Mode->CursorRow * MaxColumn + Mode->CursorColumn - 1] & EFI_WIDE_ATTRIBUTE\r
1174             ) {\r
1175           Mode->CursorColumn--;\r
1176 \r
1177           //\r
1178           // Insert an extra backspace\r
1179           //\r
1180           InsertChar  = CHAR_BACKSPACE;\r
1181           PStr        = WString + 1;\r
1182           while (*PStr != L'\0') {\r
1183             TempChar    = *PStr;\r
1184             *PStr       = InsertChar;\r
1185             InsertChar  = TempChar;\r
1186             PStr++;\r
1187           }\r
1188 \r
1189           *PStr     = InsertChar;\r
1190           *(++PStr) = 0;\r
1191 \r
1192           WString++;\r
1193         }\r
1194       }\r
1195 \r
1196       WString++;\r
1197 \r
1198     } else if (*WString == CHAR_LINEFEED) {\r
1199       //\r
1200       // If the cursor is at the bottom of the display,\r
1201       // then scroll the display one row, and do not update\r
1202       // the cursor position. Otherwise, move the cursor down one row.\r
1203       //\r
1204       if (Mode->CursorRow == (INT32) (LastRow)) {\r
1205         //\r
1206         // Scroll Screen Up One Row\r
1207         //\r
1208         SizeAttribute = LastRow * MaxColumn;\r
1209         CopyMem (\r
1210           NullAttributes,\r
1211           NullAttributes + MaxColumn,\r
1212           SizeAttribute * sizeof (INT32)\r
1213           );\r
1214 \r
1215         //\r
1216         // Each row has an ending CHAR_NULL. So one more character each line\r
1217         // for DevNullScreen than DevNullAttributes\r
1218         //\r
1219         SizeScreen = SizeAttribute + LastRow;\r
1220         CopyMem (\r
1221           NullScreen,\r
1222           NullScreen + (MaxColumn + 1),\r
1223           SizeScreen * sizeof (CHAR16)\r
1224           );\r
1225 \r
1226         //\r
1227         // Print Blank Line at last line\r
1228         //\r
1229         Screen    = NullScreen + SizeScreen;\r
1230         Attribute = NullAttributes + SizeAttribute;\r
1231 \r
1232         for (Index = 0; Index < MaxColumn; Index++, Screen++, Attribute++) {\r
1233           *Screen     = ' ';\r
1234           *Attribute  = Mode->Attribute;\r
1235         }\r
1236       } else {\r
1237         Mode->CursorRow++;\r
1238       }\r
1239 \r
1240       WString++;\r
1241     } else if (*WString == CHAR_CARRIAGE_RETURN) {\r
1242       //\r
1243       // Move the cursor to the beginning of the current row.\r
1244       //\r
1245       Mode->CursorColumn = 0;\r
1246       WString++;\r
1247     } else {\r
1248       //\r
1249       // Print the character at the current cursor position and\r
1250       // move the cursor right one column. If this moves the cursor\r
1251       // past the right edge of the display, then the line should wrap to\r
1252       // the beginning of the next line. This is equivalent to inserting\r
1253       // a CR and an LF. Note that if the cursor is at the bottom of the\r
1254       // display, and the line wraps, then the display will be scrolled\r
1255       // one line.\r
1256       //\r
1257       Index = Mode->CursorRow * MaxColumn + Mode->CursorColumn;\r
1258 \r
1259       while (Mode->CursorColumn < (INT32) MaxColumn) {\r
1260         if (*WString == CHAR_NULL) {\r
1261           break;\r
1262         }\r
1263 \r
1264         if (*WString == CHAR_BACKSPACE) {\r
1265           break;\r
1266         }\r
1267 \r
1268         if (*WString == CHAR_LINEFEED) {\r
1269           break;\r
1270         }\r
1271 \r
1272         if (*WString == CHAR_CARRIAGE_RETURN) {\r
1273           break;\r
1274         }\r
1275 \r
1276         if (*WString == UNICODE_WIDE_CHAR || *WString == UNICODE_NARROW_CHAR) {\r
1277           CurrentWidth = (*WString == UNICODE_WIDE_CHAR) ? 2 : 1;\r
1278           WString++;\r
1279           continue;\r
1280         }\r
1281 \r
1282         if (Mode->CursorColumn + CurrentWidth > (INT32) MaxColumn) {\r
1283           //\r
1284           // If a wide char is at the rightmost column, then move the char\r
1285           // to the beginning of the next row\r
1286           //\r
1287           NullScreen[Index + Mode->CursorRow] = L' ';\r
1288           NullAttributes[Index]               = Mode->Attribute | (UINT32) EFI_WIDE_ATTRIBUTE;\r
1289           Index++;\r
1290           Mode->CursorColumn++;\r
1291         } else {\r
1292           NullScreen[Index + Mode->CursorRow] = *WString;\r
1293           NullAttributes[Index]               = Mode->Attribute;\r
1294           if (CurrentWidth == 1) {\r
1295             NullAttributes[Index] &= (~ (UINT32) EFI_WIDE_ATTRIBUTE);\r
1296           } else {\r
1297             NullAttributes[Index] |= (UINT32) EFI_WIDE_ATTRIBUTE;\r
1298             NullAttributes[Index + 1] &= (~ (UINT32) EFI_WIDE_ATTRIBUTE);\r
1299           }\r
1300 \r
1301           Index += CurrentWidth;\r
1302           WString++;\r
1303           Mode->CursorColumn += CurrentWidth;\r
1304         }\r
1305       }\r
1306       //\r
1307       // At the end of line, output carriage return and line feed\r
1308       //\r
1309       if (Mode->CursorColumn >= (INT32) MaxColumn) {\r
1310         DevNullTextOutOutputString (Private, mCrLfString);\r
1311       }\r
1312     }\r
1313   }\r
1314 \r
1315   return EFI_SUCCESS;\r
1316 }\r
1317 \r
1318 \r
1319 /**\r
1320   Sets the output device(s) to a specified mode.\r
1321 \r
1322   @param  Private                 Private data structure pointer.\r
1323   @param  ModeNumber              The mode number to set.\r
1324 \r
1325   @retval EFI_SUCCESS             The requested text mode was set.\r
1326   @retval EFI_DEVICE_ERROR        The device had an error and could not complete\r
1327                                   the request.\r
1328   @retval EFI_UNSUPPORTED         The mode number was not valid.\r
1329   @retval EFI_OUT_OF_RESOURCES    Out of resources.\r
1330 \r
1331 **/\r
1332 EFI_STATUS\r
1333 DevNullTextOutSetMode (\r
1334   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private,\r
1335   IN  UINTN                           ModeNumber\r
1336   )\r
1337 {\r
1338   UINTN                         Size;\r
1339   INT32                         CurrentMode;\r
1340   UINTN                         Row;\r
1341   UINTN                         Column;\r
1342   TEXT_OUT_SPLITTER_QUERY_DATA  *Mode;\r
1343 \r
1344   //\r
1345   // No extra check for ModeNumber here, as it has been checked in\r
1346   // ConSplitterTextOutSetMode. And mode 0 should always be supported.\r
1347   // Row and Column should be fetched from intersection map.\r
1348   //\r
1349   if (Private->TextOutModeMap != NULL) {\r
1350     CurrentMode = *(Private->TextOutModeMap + Private->TextOutListCount * ModeNumber);\r
1351   } else {\r
1352     CurrentMode = (INT32)(ModeNumber);\r
1353   }\r
1354   Mode    = &(Private->TextOutQueryData[CurrentMode]);\r
1355   Row     = Mode->Rows;\r
1356   Column  = Mode->Columns;\r
1357 \r
1358   if (Row <= 0 && Column <= 0) {\r
1359     return EFI_UNSUPPORTED;\r
1360   }\r
1361 \r
1362   if (Private->TextOutMode.Mode != (INT32) ModeNumber) {\r
1363 \r
1364     Private->TextOutMode.Mode = (INT32) ModeNumber;\r
1365     Private->DevNullColumns   = Column;\r
1366     Private->DevNullRows      = Row;\r
1367 \r
1368     if (Private->DevNullScreen != NULL) {\r
1369       FreePool (Private->DevNullScreen);\r
1370     }\r
1371 \r
1372     Size                    = (Row * (Column + 1)) * sizeof (CHAR16);\r
1373     Private->DevNullScreen  = AllocateZeroPool (Size);\r
1374     if (Private->DevNullScreen == NULL) {\r
1375       return EFI_OUT_OF_RESOURCES;\r
1376     }\r
1377 \r
1378     if (Private->DevNullAttributes != NULL) {\r
1379       FreePool (Private->DevNullAttributes);\r
1380     }\r
1381 \r
1382     Size                        = Row * Column * sizeof (INT32);\r
1383     Private->DevNullAttributes  = AllocateZeroPool (Size);\r
1384     if (Private->DevNullAttributes == NULL) {\r
1385       return EFI_OUT_OF_RESOURCES;\r
1386     }\r
1387   }\r
1388 \r
1389   DevNullTextOutClearScreen (Private);\r
1390 \r
1391   return EFI_SUCCESS;\r
1392 }\r
1393 \r
1394 \r
1395 /**\r
1396   Clears the output device(s) display to the currently selected background\r
1397   color.\r
1398 \r
1399   @param  Private                 Protocol instance pointer.\r
1400 \r
1401   @retval EFI_SUCCESS             The operation completed successfully.\r
1402   @retval EFI_DEVICE_ERROR        The device had an error and could not complete\r
1403                                   the request.\r
1404   @retval EFI_UNSUPPORTED         The output device is not in a valid text mode.\r
1405 \r
1406 **/\r
1407 EFI_STATUS\r
1408 DevNullTextOutClearScreen (\r
1409   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private\r
1410   )\r
1411 {\r
1412   UINTN   Row;\r
1413   UINTN   Column;\r
1414   CHAR16  *Screen;\r
1415   INT32   *Attributes;\r
1416   INT32   CurrentAttribute;\r
1417 \r
1418   //\r
1419   // Clear the DevNull Text Out Buffers.\r
1420   // The screen is filled with spaces.\r
1421   // The attributes are all synced with the current Simple Text Out Attribute\r
1422   //\r
1423   Screen            = Private->DevNullScreen;\r
1424   Attributes        = Private->DevNullAttributes;\r
1425   CurrentAttribute  = Private->TextOutMode.Attribute;\r
1426 \r
1427   for (Row = 0; Row < Private->DevNullRows; Row++) {\r
1428     for (Column = 0; Column < Private->DevNullColumns; Column++, Screen++, Attributes++) {\r
1429       *Screen     = ' ';\r
1430       *Attributes = CurrentAttribute;\r
1431     }\r
1432     //\r
1433     // Each line of the screen has a NULL on the end so we must skip over it\r
1434     //\r
1435     Screen++;\r
1436   }\r
1437 \r
1438   DevNullTextOutSetCursorPosition (Private, 0, 0);\r
1439 \r
1440   return DevNullTextOutEnableCursor (Private, TRUE);\r
1441 }\r
1442 \r
1443 \r
1444 /**\r
1445   Sets the current coordinates of the cursor position.\r
1446 \r
1447   @param  Private                 Protocol instance pointer.\r
1448   @param  Column                  \r
1449   @param  Row                     the position to set the cursor to. Must be\r
1450                                   greater than or equal to zero and less than the\r
1451                                   number of columns and rows by QueryMode ().\r
1452 \r
1453   @retval EFI_SUCCESS             The operation completed successfully.\r
1454   @retval EFI_DEVICE_ERROR        The device had an error and could not complete\r
1455                                   the request.\r
1456   @retval EFI_UNSUPPORTED         The output device is not in a valid text mode, or\r
1457                                   the cursor position is invalid for the current\r
1458                                   mode.\r
1459 \r
1460 **/\r
1461 EFI_STATUS\r
1462 DevNullTextOutSetCursorPosition (\r
1463   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private,\r
1464   IN  UINTN                           Column,\r
1465   IN  UINTN                           Row\r
1466   )\r
1467 {\r
1468   //\r
1469   // No need to do extra check here as whether (Column, Row) is valid has\r
1470   // been checked in ConSplitterTextOutSetCursorPosition. And (0, 0) should\r
1471   // always be supported.\r
1472   //\r
1473   Private->TextOutMode.CursorColumn = (INT32) Column;\r
1474   Private->TextOutMode.CursorRow    = (INT32) Row;\r
1475 \r
1476   return EFI_SUCCESS;\r
1477 }\r
1478 \r
1479 \r
1480 /**\r
1481   Implements SIMPLE_TEXT_OUTPUT.EnableCursor().\r
1482   In this driver, the cursor cannot be hidden.\r
1483 \r
1484   @param  Private                 Indicates the calling context.\r
1485   @param  Visible                 If TRUE, the cursor is set to be visible, If\r
1486                                   FALSE, the cursor is set to be invisible.\r
1487 \r
1488   @retval EFI_SUCCESS             The request is valid.\r
1489 \r
1490 **/\r
1491 EFI_STATUS\r
1492 DevNullTextOutEnableCursor (\r
1493   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private,\r
1494   IN  BOOLEAN                         Visible\r
1495   )\r
1496 {\r
1497   Private->TextOutMode.CursorVisible = Visible;\r
1498 \r
1499   return EFI_SUCCESS;\r
1500 }\r
1501 \r
1502 \r
1503 /**\r
1504   Take the DevNull TextOut device and update the Simple Text Out on every\r
1505   UGA device.\r
1506 \r
1507   @param  Private                 Indicates the calling context.\r
1508 \r
1509   @retval EFI_SUCCESS             The request is valid.\r
1510   @retval other                   Return status of TextOut->OutputString ()\r
1511 \r
1512 **/\r
1513 EFI_STATUS\r
1514 DevNullSyncStdOut (\r
1515   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private\r
1516   )\r
1517 {\r
1518   EFI_STATUS                       Status;\r
1519   EFI_STATUS                       ReturnStatus;\r
1520   UINTN                            Row;\r
1521   UINTN                            Column;\r
1522   UINTN                            List;\r
1523   UINTN                            MaxColumn;\r
1524   UINTN                            CurrentColumn;\r
1525   UINTN                            StartRow;\r
1526   UINTN                            StartColumn;\r
1527   INT32                            StartAttribute;\r
1528   BOOLEAN                          StartCursorState;\r
1529   CHAR16                           *Screen;\r
1530   CHAR16                           *Str;\r
1531   CHAR16                           *Buffer;\r
1532   CHAR16                           *BufferTail;\r
1533   CHAR16                           *ScreenStart;\r
1534   INT32                            CurrentAttribute;\r
1535   INT32                            *Attributes;\r
1536   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *Sto;\r
1537 \r
1538   //\r
1539   // Save the devices Attributes, Cursor enable state and location\r
1540   //\r
1541   StartColumn       = Private->TextOutMode.CursorColumn;\r
1542   StartRow          = Private->TextOutMode.CursorRow;\r
1543   StartAttribute    = Private->TextOutMode.Attribute;\r
1544   StartCursorState  = Private->TextOutMode.CursorVisible;\r
1545 \r
1546   for (List = 0; List < Private->CurrentNumberOfConsoles; List++) {\r
1547 \r
1548     Sto = Private->TextOutList[List].TextOut;\r
1549 \r
1550     //\r
1551     // Skip non GOP/UGA devices\r
1552     //\r
1553     if ((Private->TextOutList[List].GraphicsOutput != NULL) || (Private->TextOutList[List].UgaDraw != NULL)) {\r
1554       Sto->EnableCursor (Sto, FALSE);\r
1555       Sto->ClearScreen (Sto);\r
1556     }\r
1557   }\r
1558 \r
1559   ReturnStatus  = EFI_SUCCESS;\r
1560   Screen        = Private->DevNullScreen;\r
1561   Attributes    = Private->DevNullAttributes;\r
1562   MaxColumn     = Private->DevNullColumns;\r
1563 \r
1564   Buffer        = AllocateZeroPool ((MaxColumn + 1) * sizeof (CHAR16));\r
1565   if (Buffer == NULL) {\r
1566     return ReturnStatus;\r
1567   }\r
1568 \r
1569   for (Row = 0; Row < Private->DevNullRows; Row++, Screen += (MaxColumn + 1), Attributes += MaxColumn) {\r
1570 \r
1571     if (Row == (Private->DevNullRows - 1)) {\r
1572       //\r
1573       // Don't ever sync the last character as it will scroll the screen\r
1574       //\r
1575       Screen[MaxColumn - 1] = 0x00;\r
1576     }\r
1577 \r
1578     Column = 0;\r
1579     while (Column < MaxColumn) {\r
1580       if (Screen[Column] > 0) {\r
1581         CurrentAttribute  = Attributes[Column];\r
1582         CurrentColumn     = Column;\r
1583         ScreenStart       = &Screen[Column];\r
1584 \r
1585         //\r
1586         // the line end is alway 0x0. So Column should be less than MaxColumn\r
1587         // It should be still in the same row\r
1588         //\r
1589         for (Str = ScreenStart, BufferTail = Buffer; *Str != 0; Str++, Column++) {\r
1590 \r
1591           if (Attributes[Column] != CurrentAttribute) {\r
1592             Column--;\r
1593             break;\r
1594           }\r
1595 \r
1596           *BufferTail = *Str;\r
1597           BufferTail++;\r
1598           if ((Attributes[Column] & EFI_WIDE_ATTRIBUTE) != 0) {\r
1599             Str++;\r
1600             Column++;\r
1601           }\r
1602         }\r
1603 \r
1604         *BufferTail = 0;\r
1605 \r
1606         for (List = 0; List < Private->CurrentNumberOfConsoles; List++) {\r
1607 \r
1608           Sto = Private->TextOutList[List].TextOut;\r
1609 \r
1610           //\r
1611           // Skip non GOP/UGA devices\r
1612           //\r
1613           if ((Private->TextOutList[List].GraphicsOutput != NULL) || (Private->TextOutList[List].UgaDraw != NULL)) {\r
1614             Sto->SetAttribute (Sto, CurrentAttribute);\r
1615             Sto->SetCursorPosition (Sto, CurrentColumn, Row);\r
1616             Status = Sto->OutputString (Sto, Buffer);\r
1617             if (EFI_ERROR (Status)) {\r
1618               ReturnStatus = Status;\r
1619             }\r
1620           }\r
1621         }\r
1622 \r
1623       }\r
1624 \r
1625       Column++;\r
1626     }\r
1627   }\r
1628   //\r
1629   // Restore the devices Attributes, Cursor enable state and location\r
1630   //\r
1631   for (List = 0; List < Private->CurrentNumberOfConsoles; List++) {\r
1632     Sto = Private->TextOutList[List].TextOut;\r
1633 \r
1634     //\r
1635     // Skip non GOP/UGA devices\r
1636     //\r
1637     if ((Private->TextOutList[List].GraphicsOutput != NULL) || (Private->TextOutList[List].UgaDraw != NULL)) {\r
1638       Sto->SetAttribute (Sto, StartAttribute);\r
1639       Sto->SetCursorPosition (Sto, StartColumn, StartRow);\r
1640       Status = Sto->EnableCursor (Sto, StartCursorState);\r
1641       if (EFI_ERROR (Status)) {\r
1642         ReturnStatus = Status;\r
1643       }\r
1644     }\r
1645   }\r
1646 \r
1647   FreePool (Buffer);\r
1648 \r
1649   return ReturnStatus;\r
1650 }\r