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