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