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