Add check of buffer value returned from AllocateZeroPool()
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Universal / Console / ConSplitterDxe / ConSplitterGraphics.c
1 /*++\r
2 \r
3 Copyright (c) 2006 - 2007, Intel Corporation\r
4 All rights reserved. This program and the accompanying materials\r
5 are licensed and made available under the terms and conditions of the BSD License\r
6 which accompanies this distribution.  The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php\r
8 \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11 \r
12 Module Name:\r
13 \r
14   ConSplitterGraphics.c\r
15 \r
16 Abstract:\r
17 \r
18   Support for ConsoleControl protocol. Support for UGA Draw spliter.\r
19   Support for DevNull Console Out. This console uses memory buffers\r
20   to represnt the console. It allows a console to start very early and\r
21   when a new console is added it is synced up with the current console\r
22 \r
23 --*/\r
24 \r
25 #include "ConSplitter.h"\r
26 \r
27 \r
28 static CHAR16 mCrLfString[3] = { CHAR_CARRIAGE_RETURN, CHAR_LINEFEED, CHAR_NULL };\r
29 \r
30 EFI_STATUS\r
31 EFIAPI\r
32 ConSpliterConsoleControlGetMode (\r
33   IN  EFI_CONSOLE_CONTROL_PROTOCOL    *This,\r
34   OUT EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode,\r
35   OUT BOOLEAN                         *GopExists,\r
36   OUT BOOLEAN                         *StdInLocked\r
37   )\r
38 /*++\r
39 \r
40   Routine Description:\r
41     Return the current video mode information. Also returns info about existence\r
42     of UGA Draw devices in system, and if the Std In device is locked. All the\r
43     arguments are optional and only returned if a non NULL pointer is passed in.\r
44 \r
45   Arguments:\r
46     This - Protocol instance pointer.\r
47     Mode        - Are we in text of grahics mode.\r
48     UgaExists   - TRUE if UGA Spliter has found a UGA device\r
49     StdInLocked - TRUE if StdIn device is keyboard locked\r
50 \r
51   Returns:\r
52     EFI_SUCCESS - Mode information returned.\r
53     EFI_INVALID_PARAMETER - Invalid parameters.\r
54 \r
55 --*/\r
56 {\r
57   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;\r
58   UINTN                           Index;\r
59 \r
60   Private = CONSOLE_CONTROL_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
61 \r
62   if (Mode == NULL) {\r
63     return EFI_INVALID_PARAMETER;\r
64   }\r
65 \r
66   *Mode = Private->ConsoleOutputMode;\r
67 \r
68   if (GopExists != NULL) {\r
69     *GopExists = FALSE;\r
70     for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {\r
71       if ((Private->TextOutList[Index].GraphicsOutput != NULL) || (Private->TextOutList[Index].UgaDraw != NULL)) {\r
72         *GopExists = TRUE;\r
73         break;\r
74       }\r
75     }\r
76   }\r
77 \r
78   if (StdInLocked != NULL) {\r
79     *StdInLocked = ConSpliterConssoleControlStdInLocked ();\r
80   }\r
81 \r
82   return EFI_SUCCESS;\r
83 }\r
84 \r
85 EFI_STATUS\r
86 EFIAPI\r
87 ConSpliterConsoleControlSetMode (\r
88   IN  EFI_CONSOLE_CONTROL_PROTOCOL    *This,\r
89   IN  EFI_CONSOLE_CONTROL_SCREEN_MODE Mode\r
90   )\r
91 /*++\r
92 \r
93   Routine Description:\r
94     Set the current mode to either text or graphics. Graphics is\r
95     for Quiet Boot.\r
96 \r
97   Arguments:\r
98     This  - Protocol instance pointer.\r
99     Mode  - Mode to set the\r
100 \r
101   Returns:\r
102     EFI_SUCCESS     - Mode information returned.\r
103     EFI_INVALID_PARAMETER - Invalid parameter.\r
104     EFI_UNSUPPORTED - Operation unsupported.\r
105 \r
106 --*/\r
107 {\r
108   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;\r
109   UINTN                           Index;\r
110   TEXT_OUT_AND_GOP_DATA           *TextAndGop;\r
111   BOOLEAN                         Supported;\r
112 \r
113   Private = CONSOLE_CONTROL_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
114 \r
115   if (Mode >= EfiConsoleControlScreenMaxValue) {\r
116     return EFI_INVALID_PARAMETER;\r
117   }\r
118 \r
119   //\r
120   // Judge current mode with wanted mode at first.\r
121   //\r
122   if (Private->ConsoleOutputMode == Mode) {\r
123     return EFI_SUCCESS;\r
124   }\r
125 \r
126   Supported   = FALSE;\r
127   TextAndGop  = &Private->TextOutList[0];\r
128   for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++, TextAndGop++) {\r
129     if ((TextAndGop->GraphicsOutput != NULL) || (TextAndGop->UgaDraw != NULL)) {\r
130       Supported = TRUE;\r
131       break;\r
132     }\r
133   }\r
134 \r
135   if ((!Supported) && (Mode == EfiConsoleControlScreenGraphics)) {\r
136     return EFI_UNSUPPORTED;\r
137   }\r
138 \r
139   Private->ConsoleOutputMode  = Mode;\r
140 \r
141   TextAndGop = &Private->TextOutList[0];\r
142   for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++, TextAndGop++) {\r
143 \r
144     TextAndGop->TextOutEnabled = TRUE;\r
145     //\r
146     // If we are going into Graphics mode disable ConOut to any UGA device\r
147     //\r
148     if ((Mode == EfiConsoleControlScreenGraphics) &&((TextAndGop->GraphicsOutput != NULL) || (TextAndGop->UgaDraw != NULL))) {\r
149       TextAndGop->TextOutEnabled = FALSE;\r
150       DevNullGopSync (Private, TextAndGop->GraphicsOutput, TextAndGop->UgaDraw);\r
151     }\r
152   }\r
153 \r
154   if (Mode == EfiConsoleControlScreenText) {\r
155     DevNullSyncGopStdOut (Private);\r
156   }\r
157 \r
158   return EFI_SUCCESS;\r
159 }\r
160 \r
161 EFI_STATUS\r
162 EFIAPI\r
163 ConSpliterGraphicsOutputQueryMode (\r
164   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL          *This,\r
165   IN  UINT32                                ModeNumber,\r
166   OUT UINTN                                 *SizeOfInfo,\r
167   OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  **Info\r
168   )\r
169 /*++\r
170 \r
171   Routine Description:\r
172     Return the current video mode information.\r
173 \r
174   Arguments:\r
175     This                  - Protocol instance pointer.\r
176     ModeNumber            - The mode number to return information on.\r
177     Info                  - Caller allocated buffer that returns information about ModeNumber.\r
178     SizeOfInfo            - A pointer to the size, in bytes, of the Info buffer.\r
179 \r
180   Returns:\r
181     EFI_SUCCESS           - Mode information returned.\r
182     EFI_BUFFER_TOO_SMALL  - The Info buffer was too small.\r
183     EFI_DEVICE_ERROR      - A hardware error occurred trying to retrieve the video mode.\r
184     EFI_NOT_STARTED       - Video display is not initialized. Call SetMode ()\r
185     EFI_INVALID_PARAMETER - One of the input args was NULL.\r
186 \r
187 --*/\r
188 {\r
189   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;\r
190   TEXT_OUT_GOP_MODE               *Mode;\r
191 \r
192   if (This == NULL || Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) {\r
193     return EFI_INVALID_PARAMETER;\r
194   }\r
195 \r
196   //\r
197   // retrieve private data\r
198   //\r
199   Private = GRAPHICS_OUTPUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
200 \r
201   if (Private->HardwareNeedsStarting) {\r
202     return EFI_NOT_STARTED;\r
203   }\r
204 \r
205   *Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));\r
206 \r
207   if (*Info == NULL) {\r
208     return EFI_OUT_OF_RESOURCES;\r
209   }\r
210 \r
211   *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);\r
212 \r
213   CopyMem (*Info, Private->GraphicsOutput.Mode->Info, *SizeOfInfo);\r
214   Mode = &Private->GraphicsOutputModeBuffer[ModeNumber];\r
215   (*Info)->HorizontalResolution = Mode->HorizontalResolution;\r
216   (*Info)->VerticalResolution = Mode->VerticalResolution;\r
217   (*Info)->PixelsPerScanLine = Mode->HorizontalResolution;\r
218 \r
219   return EFI_SUCCESS;\r
220 }\r
221 \r
222 EFI_STATUS\r
223 EFIAPI\r
224 ConSpliterGraphicsOutputSetMode (\r
225   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL * This,\r
226   IN  UINT32                       ModeNumber\r
227   )\r
228 /*++\r
229 \r
230 Routine Description:\r
231 \r
232   Graphics output protocol interface to set video mode\r
233 \r
234   Arguments:\r
235     This             - Protocol instance pointer.\r
236     ModeNumber       - The mode number to be set.\r
237 \r
238   Returns:\r
239     EFI_SUCCESS      - Graphics mode was changed.\r
240     EFI_DEVICE_ERROR - The device had an error and could not complete the request.\r
241     EFI_UNSUPPORTED  - ModeNumber is not supported by this device.\r
242 \r
243 --*/\r
244 {\r
245   EFI_STATUS                             Status;\r
246   TEXT_OUT_SPLITTER_PRIVATE_DATA         *Private;\r
247   UINTN                                  Index;\r
248   EFI_STATUS                             ReturnStatus;\r
249   TEXT_OUT_GOP_MODE                      *Mode;\r
250   UINTN                                  Size;\r
251   EFI_GRAPHICS_OUTPUT_PROTOCOL           *GraphicsOutput;\r
252   UINTN                                  NumberIndex;\r
253   UINTN                                  SizeOfInfo;\r
254   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION   *Info;\r
255   EFI_UGA_DRAW_PROTOCOL                  *UgaDraw;\r
256 \r
257   if (ModeNumber >= This->Mode->MaxMode) {\r
258     return EFI_UNSUPPORTED;\r
259   }\r
260 \r
261   if (ModeNumber == This->Mode->Mode) {\r
262     return EFI_SUCCESS;\r
263   }\r
264 \r
265   Private = GRAPHICS_OUTPUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
266 \r
267   //\r
268   // GopDevNullSetMode ()\r
269   //\r
270   ReturnStatus = EFI_SUCCESS;\r
271 \r
272   //\r
273   // Free the old version\r
274   //\r
275   if (Private->GraphicsOutputBlt != NULL) {\r
276     FreePool (Private->GraphicsOutputBlt);\r
277   }\r
278 \r
279   //\r
280   // Allocate the virtual Blt buffer\r
281   //\r
282   Mode = &Private->GraphicsOutputModeBuffer[ModeNumber];\r
283   Size = Mode->HorizontalResolution * Mode->VerticalResolution * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);\r
284   Private->GraphicsOutputBlt = AllocateZeroPool (Size);\r
285 \r
286   if (Private->GraphicsOutputBlt == NULL) {\r
287     return EFI_OUT_OF_RESOURCES;\r
288   }\r
289 \r
290   if (!Private->HardwareNeedsStarting) {\r
291     if (Private->ConsoleOutputMode != EfiConsoleControlScreenGraphics) {\r
292       return EFI_UNSUPPORTED;\r
293     }\r
294   }\r
295   //\r
296   // return the worst status met\r
297   //\r
298   for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {\r
299     GraphicsOutput = Private->TextOutList[Index].GraphicsOutput;\r
300     if (GraphicsOutput != NULL) {\r
301       //\r
302       // Find corresponding ModeNumber of this GraphicsOutput instance\r
303       //\r
304       for (NumberIndex = 0; NumberIndex < GraphicsOutput->Mode->MaxMode; NumberIndex ++) {\r
305         Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) NumberIndex, &SizeOfInfo, &Info);\r
306         if (EFI_ERROR (Status)) {\r
307           return Status;\r
308         }\r
309         if ((Info->HorizontalResolution == Mode->HorizontalResolution) && (Info->VerticalResolution == Mode->VerticalResolution)) {\r
310           FreePool (Info);\r
311           break;\r
312         }\r
313         FreePool (Info);\r
314       }\r
315 \r
316       Status = GraphicsOutput->SetMode (GraphicsOutput, (UINT32) NumberIndex);\r
317       if (EFI_ERROR (Status)) {\r
318         ReturnStatus = Status;\r
319       }\r
320     }\r
321 \r
322     UgaDraw = Private->TextOutList[Index].UgaDraw;\r
323     if (UgaDraw != NULL) {\r
324       Status = UgaDraw->SetMode (\r
325                           UgaDraw,\r
326                           Mode->HorizontalResolution,\r
327                           Mode->VerticalResolution,\r
328                           32,\r
329                           60\r
330                           );\r
331       if (EFI_ERROR (Status)) {\r
332         ReturnStatus = Status;\r
333       }\r
334     }\r
335   }\r
336 \r
337   This->Mode->Mode = ModeNumber;\r
338 \r
339   Info = This->Mode->Info;\r
340   Info->HorizontalResolution = Mode->HorizontalResolution;\r
341   Info->VerticalResolution   = Mode->VerticalResolution;\r
342   Info->PixelsPerScanLine    = Mode->HorizontalResolution;\r
343 \r
344   //\r
345   // Information is not enough here, so the following items remain unchanged:\r
346   //  GraphicsOutputMode->Info->Version, GraphicsOutputMode->Info->PixelFormat\r
347   //  GraphicsOutputMode->SizeOfInfo, GraphicsOutputMode->FrameBufferBase, GraphicsOutputMode->FrameBufferSize\r
348   // These items will be initialized/updated when a new GOP device is added into ConsoleSplitter.\r
349   //\r
350 \r
351   Private->HardwareNeedsStarting = FALSE;\r
352 \r
353   return ReturnStatus;\r
354 }\r
355 \r
356 STATIC\r
357 EFI_STATUS\r
358 DevNullGraphicsOutputBlt (\r
359   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA                *Private,\r
360   IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL                 *BltBuffer, OPTIONAL\r
361   IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION             BltOperation,\r
362   IN  UINTN                                         SourceX,\r
363   IN  UINTN                                         SourceY,\r
364   IN  UINTN                                         DestinationX,\r
365   IN  UINTN                                         DestinationY,\r
366   IN  UINTN                                         Width,\r
367   IN  UINTN                                         Height,\r
368   IN  UINTN                                         Delta         OPTIONAL\r
369   )\r
370 {\r
371   UINTN                         SrcY;\r
372   BOOLEAN                       Forward;\r
373   UINTN                         Index;\r
374   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltPtr;\r
375   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *ScreenPtr;\r
376   UINTN                         HorizontalResolution;\r
377   UINTN                         VerticalResolution;\r
378 \r
379   if ((BltOperation < EfiBltVideoFill) || (BltOperation >= EfiGraphicsOutputBltOperationMax)) {\r
380     return EFI_INVALID_PARAMETER;\r
381   }\r
382 \r
383   if (Width == 0 || Height == 0) {\r
384     return EFI_INVALID_PARAMETER;\r
385   }\r
386 \r
387   if (Delta == 0) {\r
388     Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);\r
389   }\r
390 \r
391   HorizontalResolution  = Private->GraphicsOutput.Mode->Info->HorizontalResolution;\r
392   VerticalResolution    = Private->GraphicsOutput.Mode->Info->VerticalResolution;\r
393 \r
394   //\r
395   // We need to fill the Virtual Screen buffer with the blt data.\r
396   //\r
397   if (BltOperation == EfiBltVideoToBltBuffer) {\r
398     //\r
399     // Video to BltBuffer: Source is Video, destination is BltBuffer\r
400     //\r
401     if ((SourceY + Height) > VerticalResolution) {\r
402       return EFI_INVALID_PARAMETER;\r
403     }\r
404 \r
405     if ((SourceX + Width) > HorizontalResolution) {\r
406       return EFI_INVALID_PARAMETER;\r
407     }\r
408 \r
409     BltPtr    = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + DestinationY * Delta + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
410     ScreenPtr = &Private->GraphicsOutputBlt[SourceY * HorizontalResolution + SourceX];\r
411     while (Height) {\r
412       CopyMem (BltPtr, ScreenPtr, Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
413       BltPtr = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltPtr + Delta);\r
414       ScreenPtr += HorizontalResolution;\r
415       Height--;\r
416     }\r
417   } else {\r
418     //\r
419     // BltBuffer to Video: Source is BltBuffer, destination is Video\r
420     //\r
421     if (DestinationY + Height > VerticalResolution) {\r
422       return EFI_INVALID_PARAMETER;\r
423     }\r
424 \r
425     if (DestinationX + Width > HorizontalResolution) {\r
426       return EFI_INVALID_PARAMETER;\r
427     }\r
428 \r
429     if ((BltOperation == EfiBltVideoToVideo) && (DestinationY > SourceY)) {\r
430       //\r
431       // Copy backwards, only care the Video to Video Blt\r
432       //\r
433       ScreenPtr = &Private->GraphicsOutputBlt[(DestinationY + Height - 1) * HorizontalResolution + DestinationX];\r
434       SrcY      = SourceY + Height - 1;\r
435       Forward   = FALSE;\r
436     } else {\r
437       //\r
438       // Copy forwards, for other cases\r
439       //\r
440       ScreenPtr = &Private->GraphicsOutputBlt[DestinationY * HorizontalResolution + DestinationX];\r
441       SrcY      = SourceY;\r
442       Forward   = TRUE;\r
443     }\r
444 \r
445     while (Height != 0) {\r
446       if (BltOperation == EfiBltVideoFill) {\r
447         for (Index = 0; Index < Width; Index++) {\r
448           ScreenPtr[Index] = *BltBuffer;\r
449         }\r
450       } else {\r
451         if (BltOperation == EfiBltBufferToVideo) {\r
452           BltPtr = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + SrcY * Delta + SourceX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
453         } else {\r
454           BltPtr = &Private->GraphicsOutputBlt[SrcY * HorizontalResolution + SourceX];\r
455         }\r
456 \r
457         CopyMem (ScreenPtr, BltPtr, Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
458       }\r
459 \r
460       if (Forward) {\r
461         ScreenPtr += HorizontalResolution;\r
462         SrcY ++;\r
463       } else {\r
464         ScreenPtr -= HorizontalResolution;\r
465         SrcY --;\r
466       }\r
467       Height--;\r
468     }\r
469   }\r
470 \r
471   return EFI_SUCCESS;\r
472 }\r
473 \r
474 EFI_STATUS\r
475 EFIAPI\r
476 ConSpliterGraphicsOutputBlt (\r
477   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL                  *This,\r
478   IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL                 *BltBuffer, OPTIONAL\r
479   IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION             BltOperation,\r
480   IN  UINTN                                         SourceX,\r
481   IN  UINTN                                         SourceY,\r
482   IN  UINTN                                         DestinationX,\r
483   IN  UINTN                                         DestinationY,\r
484   IN  UINTN                                         Width,\r
485   IN  UINTN                                         Height,\r
486   IN  UINTN                                         Delta         OPTIONAL\r
487   )\r
488 /*++\r
489 \r
490   Routine Description:\r
491     The following table defines actions for BltOperations:\r
492     EfiBltVideoFill - Write data from the  BltBuffer pixel (SourceX, SourceY)\r
493       directly to every pixel of the video display rectangle\r
494       (DestinationX, DestinationY)\r
495       (DestinationX + Width, DestinationY + Height).\r
496       Only one pixel will be used from the BltBuffer. Delta is NOT used.\r
497     EfiBltVideoToBltBuffer - Read data from the video display rectangle\r
498       (SourceX, SourceY) (SourceX + Width, SourceY + Height) and place it in\r
499       the BltBuffer rectangle (DestinationX, DestinationY )\r
500       (DestinationX + Width, DestinationY + Height). If DestinationX or\r
501       DestinationY is not zero then Delta must be set to the length in bytes\r
502       of a row in the BltBuffer.\r
503     EfiBltBufferToVideo - Write data from the  BltBuffer rectangle\r
504       (SourceX, SourceY) (SourceX + Width, SourceY + Height) directly to the\r
505       video display rectangle (DestinationX, DestinationY)\r
506       (DestinationX + Width, DestinationY + Height). If SourceX or SourceY is\r
507       not zero then Delta must be set to the length in bytes of a row in the\r
508       BltBuffer.\r
509     EfiBltVideoToVideo - Copy from the video display rectangle\r
510       (SourceX, SourceY) (SourceX + Width, SourceY + Height) .\r
511       to the video display rectangle (DestinationX, DestinationY)\r
512       (DestinationX + Width, DestinationY + Height).\r
513      The BltBuffer and Delta  are not used in this mode.\r
514 \r
515   Arguments:\r
516     This          - Protocol instance pointer.\r
517     BltBuffer     - Buffer containing data to blit into video buffer. This\r
518                     buffer has a size of Width*Height*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)\r
519     BltOperation  - Operation to perform on BlitBuffer and video memory\r
520     SourceX       - X coordinate of source for the BltBuffer.\r
521     SourceY       - Y coordinate of source for the BltBuffer.\r
522     DestinationX  - X coordinate of destination for the BltBuffer.\r
523     DestinationY  - Y coordinate of destination for the BltBuffer.\r
524     Width         - Width of rectangle in BltBuffer in pixels.\r
525     Height        - Hight of rectangle in BltBuffer in pixels.\r
526     Delta         -\r
527 \r
528   Returns:\r
529     EFI_SUCCESS           - The Blt operation completed.\r
530     EFI_INVALID_PARAMETER - BltOperation is not valid.\r
531     EFI_DEVICE_ERROR      - A hardware error occured writting to the video\r
532                              buffer.\r
533 \r
534 --*/\r
535 {\r
536   EFI_STATUS                      Status;\r
537   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;\r
538   UINTN                           Index;\r
539   EFI_STATUS                      ReturnStatus;\r
540   EFI_GRAPHICS_OUTPUT_PROTOCOL    *GraphicsOutput;\r
541   EFI_UGA_DRAW_PROTOCOL           *UgaDraw;\r
542 \r
543   Private = GRAPHICS_OUTPUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
544 \r
545   //\r
546   // Sync up DevNull GOP device\r
547   //\r
548   ReturnStatus = DevNullGraphicsOutputBlt (\r
549                   Private,\r
550                   BltBuffer,\r
551                   BltOperation,\r
552                   SourceX,\r
553                   SourceY,\r
554                   DestinationX,\r
555                   DestinationY,\r
556                   Width,\r
557                   Height,\r
558                   Delta\r
559                   );\r
560 \r
561   if (Private->ConsoleOutputMode != EfiConsoleControlScreenGraphics) {\r
562     return ReturnStatus;\r
563   }\r
564   //\r
565   // return the worst status met\r
566   //\r
567   for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {\r
568     GraphicsOutput = Private->TextOutList[Index].GraphicsOutput;\r
569     if (GraphicsOutput != NULL) {\r
570       Status = GraphicsOutput->Blt (\r
571                               GraphicsOutput,\r
572                               BltBuffer,\r
573                               BltOperation,\r
574                               SourceX,\r
575                               SourceY,\r
576                               DestinationX,\r
577                               DestinationY,\r
578                               Width,\r
579                               Height,\r
580                               Delta\r
581                               );\r
582       if (EFI_ERROR (Status)) {\r
583         ReturnStatus = Status;\r
584       } else if (BltOperation == EfiBltVideoToBltBuffer) {\r
585         //\r
586         // Only need to read the data into buffer one time\r
587         //\r
588         return EFI_SUCCESS;\r
589       }\r
590     }\r
591 \r
592     UgaDraw = Private->TextOutList[Index].UgaDraw;\r
593     if (UgaDraw != NULL) {\r
594       Status = UgaDraw->Blt (\r
595                               UgaDraw,\r
596                               (EFI_UGA_PIXEL *) BltBuffer,\r
597                               (EFI_UGA_BLT_OPERATION) BltOperation,\r
598                               SourceX,\r
599                               SourceY,\r
600                               DestinationX,\r
601                               DestinationY,\r
602                               Width,\r
603                               Height,\r
604                               Delta\r
605                               );\r
606       if (EFI_ERROR (Status)) {\r
607         ReturnStatus = Status;\r
608       } else if (BltOperation == EfiBltVideoToBltBuffer) {\r
609         //\r
610         // Only need to read the data into buffer one time\r
611         //\r
612         return EFI_SUCCESS;\r
613       }\r
614     }\r
615   }\r
616 \r
617   return ReturnStatus;\r
618 }\r
619 \r
620 EFI_STATUS\r
621 DevNullGopSync (\r
622   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private,\r
623   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL    *GraphicsOutput,\r
624   IN  EFI_UGA_DRAW_PROTOCOL           *UgaDraw\r
625   )\r
626 {\r
627   if (GraphicsOutput != NULL) {\r
628     return GraphicsOutput->Blt (\r
629                       GraphicsOutput,\r
630                       Private->GraphicsOutputBlt,\r
631                       EfiBltBufferToVideo,\r
632                       0,\r
633                       0,\r
634                       0,\r
635                       0,\r
636                       Private->GraphicsOutput.Mode->Info->HorizontalResolution,\r
637                       Private->GraphicsOutput.Mode->Info->VerticalResolution,\r
638                       0\r
639                       );\r
640   } else {\r
641     return UgaDraw->Blt (\r
642                       UgaDraw,\r
643                       (EFI_UGA_PIXEL *) Private->GraphicsOutputBlt,\r
644                       EfiUgaBltBufferToVideo,\r
645                       0,\r
646                       0,\r
647                       0,\r
648                       0,\r
649                       Private->GraphicsOutput.Mode->Info->HorizontalResolution,\r
650                       Private->GraphicsOutput.Mode->Info->VerticalResolution,\r
651                       0\r
652                       );\r
653   }\r
654 }\r
655 \r
656 \r
657 EFI_STATUS\r
658 DevNullTextOutOutputString (\r
659   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private,\r
660   IN  CHAR16                          *WString\r
661   )\r
662 /*++\r
663 \r
664   Routine Description:\r
665     Write a Unicode string to the output device.\r
666 \r
667   Arguments:\r
668     Private - Pointer to the console output splitter's private data. It\r
669               indicates the calling context.\r
670     WString - The NULL-terminated Unicode string to be displayed on the output\r
671               device(s). All output devices must also support the Unicode\r
672               drawing defined in this file.\r
673 \r
674   Returns:\r
675     EFI_SUCCESS            - The string was output to the device.\r
676     EFI_DEVICE_ERROR       - The device reported an error while attempting to\r
677                               output the text.\r
678     EFI_UNSUPPORTED        - The output device's mode is not currently in a\r
679                               defined text mode.\r
680     EFI_WARN_UNKNOWN_GLYPH - This warning code indicates that some of the\r
681                               characters in the Unicode string could not be\r
682                               rendered and were skipped.\r
683 \r
684 --*/\r
685 {\r
686   UINTN                       SizeScreen;\r
687   UINTN                       SizeAttribute;\r
688   UINTN                       Index;\r
689   EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;\r
690   CHAR16                      *Screen;\r
691   CHAR16                      *NullScreen;\r
692   CHAR16                      InsertChar;\r
693   CHAR16                      TempChar;\r
694   CHAR16                      *PStr;\r
695   INT32                       *Attribute;\r
696   INT32                       *NullAttributes;\r
697   INT32                       CurrentWidth;\r
698   UINTN                       LastRow;\r
699   UINTN                       MaxColumn;\r
700 \r
701   Mode            = &Private->TextOutMode;\r
702   NullScreen      = Private->DevNullScreen;\r
703   NullAttributes  = Private->DevNullAttributes;\r
704   LastRow         = Private->DevNullRows - 1;\r
705   MaxColumn       = Private->DevNullColumns;\r
706 \r
707   if (Mode->Attribute & EFI_WIDE_ATTRIBUTE) {\r
708     CurrentWidth = 2;\r
709   } else {\r
710     CurrentWidth = 1;\r
711   }\r
712 \r
713   while (*WString) {\r
714 \r
715     if (*WString == CHAR_BACKSPACE) {\r
716       //\r
717       // If the cursor is at the left edge of the display, then move the cursor\r
718       // one row up.\r
719       //\r
720       if (Mode->CursorColumn == 0 && Mode->CursorRow > 0) {\r
721         Mode->CursorRow--;\r
722         Mode->CursorColumn = (INT32) MaxColumn;\r
723       }\r
724 \r
725       //\r
726       // If the cursor is not at the left edge of the display,\r
727       // then move the cursor left one column.\r
728       //\r
729       if (Mode->CursorColumn > 0) {\r
730         Mode->CursorColumn--;\r
731         if (Mode->CursorColumn > 0 &&\r
732             NullAttributes[Mode->CursorRow * MaxColumn + Mode->CursorColumn - 1] & EFI_WIDE_ATTRIBUTE\r
733             ) {\r
734           Mode->CursorColumn--;\r
735 \r
736           //\r
737           // Insert an extra backspace\r
738           //\r
739           InsertChar  = CHAR_BACKSPACE;\r
740           PStr        = WString + 1;\r
741           while (*PStr) {\r
742             TempChar    = *PStr;\r
743             *PStr       = InsertChar;\r
744             InsertChar  = TempChar;\r
745             PStr++;\r
746           }\r
747 \r
748           *PStr     = InsertChar;\r
749           *(++PStr) = 0;\r
750 \r
751           WString++;\r
752         }\r
753       }\r
754 \r
755       WString++;\r
756 \r
757     } else if (*WString == CHAR_LINEFEED) {\r
758       //\r
759       // If the cursor is at the bottom of the display,\r
760       // then scroll the display one row, and do not update\r
761       // the cursor position. Otherwise, move the cursor down one row.\r
762       //\r
763       if (Mode->CursorRow == (INT32) (LastRow)) {\r
764         //\r
765         // Scroll Screen Up One Row\r
766         //\r
767         SizeAttribute = LastRow * MaxColumn;\r
768         CopyMem (\r
769           NullAttributes,\r
770           NullAttributes + MaxColumn,\r
771           SizeAttribute * sizeof (INT32)\r
772           );\r
773 \r
774         //\r
775         // Each row has an ending CHAR_NULL. So one more character each line\r
776         // for DevNullScreen than DevNullAttributes\r
777         //\r
778         SizeScreen = SizeAttribute + LastRow;\r
779         CopyMem (\r
780           NullScreen,\r
781           NullScreen + (MaxColumn + 1),\r
782           SizeScreen * sizeof (CHAR16)\r
783           );\r
784 \r
785         //\r
786         // Print Blank Line at last line\r
787         //\r
788         Screen    = NullScreen + SizeScreen;\r
789         Attribute = NullAttributes + SizeAttribute;\r
790 \r
791         for (Index = 0; Index < MaxColumn; Index++, Screen++, Attribute++) {\r
792           *Screen     = ' ';\r
793           *Attribute  = Mode->Attribute;\r
794         }\r
795       } else {\r
796         Mode->CursorRow++;\r
797       }\r
798 \r
799       WString++;\r
800     } else if (*WString == CHAR_CARRIAGE_RETURN) {\r
801       //\r
802       // Move the cursor to the beginning of the current row.\r
803       //\r
804       Mode->CursorColumn = 0;\r
805       WString++;\r
806     } else {\r
807       //\r
808       // Print the character at the current cursor position and\r
809       // move the cursor right one column. If this moves the cursor\r
810       // past the right edge of the display, then the line should wrap to\r
811       // the beginning of the next line. This is equivalent to inserting\r
812       // a CR and an LF. Note that if the cursor is at the bottom of the\r
813       // display, and the line wraps, then the display will be scrolled\r
814       // one line.\r
815       //\r
816       Index = Mode->CursorRow * MaxColumn + Mode->CursorColumn;\r
817 \r
818       while (Mode->CursorColumn < (INT32) MaxColumn) {\r
819         if (*WString == CHAR_NULL) {\r
820           break;\r
821         }\r
822 \r
823         if (*WString == CHAR_BACKSPACE) {\r
824           break;\r
825         }\r
826 \r
827         if (*WString == CHAR_LINEFEED) {\r
828           break;\r
829         }\r
830 \r
831         if (*WString == CHAR_CARRIAGE_RETURN) {\r
832           break;\r
833         }\r
834 \r
835         if (*WString == UNICODE_WIDE_CHAR || *WString == UNICODE_NARROW_CHAR) {\r
836           CurrentWidth = (*WString == UNICODE_WIDE_CHAR) ? 2 : 1;\r
837           WString++;\r
838           continue;\r
839         }\r
840 \r
841         if (Mode->CursorColumn + CurrentWidth > (INT32) MaxColumn) {\r
842           //\r
843           // If a wide char is at the rightmost column, then move the char\r
844           // to the beginning of the next row\r
845           //\r
846           NullScreen[Index + Mode->CursorRow] = L' ';\r
847           NullAttributes[Index]               = Mode->Attribute | (UINT32) EFI_WIDE_ATTRIBUTE;\r
848           Index++;\r
849           Mode->CursorColumn++;\r
850         } else {\r
851           NullScreen[Index + Mode->CursorRow] = *WString;\r
852           NullAttributes[Index]               = Mode->Attribute;\r
853           if (CurrentWidth == 1) {\r
854             NullAttributes[Index] &= (~ (UINT32) EFI_WIDE_ATTRIBUTE);\r
855           } else {\r
856             NullAttributes[Index] |= (UINT32) EFI_WIDE_ATTRIBUTE;\r
857             NullAttributes[Index + 1] &= (~ (UINT32) EFI_WIDE_ATTRIBUTE);\r
858           }\r
859 \r
860           Index += CurrentWidth;\r
861           WString++;\r
862           Mode->CursorColumn += CurrentWidth;\r
863         }\r
864       }\r
865       //\r
866       // At the end of line, output carriage return and line feed\r
867       //\r
868       if (Mode->CursorColumn >= (INT32) MaxColumn) {\r
869         DevNullTextOutOutputString (Private, mCrLfString);\r
870       }\r
871     }\r
872   }\r
873 \r
874   return EFI_SUCCESS;\r
875 }\r
876 \r
877 EFI_STATUS\r
878 DevNullTextOutSetMode (\r
879   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private,\r
880   IN  UINTN                           ModeNumber\r
881   )\r
882 /*++\r
883 \r
884   Routine Description:\r
885     Sets the output device(s) to a specified mode.\r
886 \r
887   Arguments:\r
888     Private    - Private data structure pointer.\r
889     ModeNumber - The mode number to set.\r
890 \r
891   Returns:\r
892     EFI_SUCCESS      - The requested text mode was set.\r
893     EFI_DEVICE_ERROR - The device had an error and\r
894                        could not complete the request.\r
895     EFI_UNSUPPORTED - The mode number was not valid.\r
896     EFI_OUT_OF_RESOURCES - Out of resources.\r
897 \r
898 --*/\r
899 {\r
900   UINTN                         Size;\r
901   UINTN                         Row;\r
902   UINTN                         Column;\r
903   TEXT_OUT_SPLITTER_QUERY_DATA  *Mode;\r
904 \r
905   //\r
906   // No extra check for ModeNumber here, as it has been checked in\r
907   // ConSplitterTextOutSetMode. And mode 0 should always be supported.\r
908   //\r
909   Mode    = &(Private->TextOutQueryData[ModeNumber]);\r
910   Row     = Mode->Rows;\r
911   Column  = Mode->Columns;\r
912 \r
913   if (Row <= 0 && Column <= 0) {\r
914     return EFI_UNSUPPORTED;\r
915   }\r
916 \r
917   if (Private->DevNullColumns != Column || Private->DevNullRows != Row) {\r
918 \r
919     Private->TextOutMode.Mode = (INT32) ModeNumber;\r
920     Private->DevNullColumns   = Column;\r
921     Private->DevNullRows      = Row;\r
922 \r
923     if (Private->DevNullScreen != NULL) {\r
924       FreePool (Private->DevNullScreen);\r
925     }\r
926 \r
927     Size                    = (Row * (Column + 1)) * sizeof (CHAR16);\r
928     Private->DevNullScreen  = AllocateZeroPool (Size);\r
929     if (Private->DevNullScreen == NULL) {\r
930       return EFI_OUT_OF_RESOURCES;\r
931     }\r
932 \r
933     if (Private->DevNullAttributes != NULL) {\r
934       FreePool (Private->DevNullAttributes);\r
935     }\r
936 \r
937     Size                        = Row * Column * sizeof (INT32);\r
938     Private->DevNullAttributes  = AllocateZeroPool (Size);\r
939     if (Private->DevNullAttributes == NULL) {\r
940       return EFI_OUT_OF_RESOURCES;\r
941     }\r
942   }\r
943 \r
944   DevNullTextOutClearScreen (Private);\r
945 \r
946   return EFI_SUCCESS;\r
947 }\r
948 \r
949 EFI_STATUS\r
950 DevNullTextOutClearScreen (\r
951   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private\r
952   )\r
953 /*++\r
954 \r
955   Routine Description:\r
956     Clears the output device(s) display to the currently selected background\r
957     color.\r
958 \r
959   Arguments:\r
960     Private     - Protocol instance pointer.\r
961 \r
962   Returns:\r
963     EFI_SUCCESS      - The operation completed successfully.\r
964     EFI_DEVICE_ERROR - The device had an error and\r
965                        could not complete the request.\r
966     EFI_UNSUPPORTED - The output device is not in a valid text mode.\r
967 \r
968 --*/\r
969 {\r
970   UINTN   Row;\r
971   UINTN   Column;\r
972   CHAR16  *Screen;\r
973   INT32   *Attributes;\r
974   INT32   CurrentAttribute;\r
975 \r
976   //\r
977   // Clear the DevNull Text Out Buffers.\r
978   // The screen is filled with spaces.\r
979   // The attributes are all synced with the current Simple Text Out Attribute\r
980   //\r
981   Screen            = Private->DevNullScreen;\r
982   Attributes        = Private->DevNullAttributes;\r
983   CurrentAttribute  = Private->TextOutMode.Attribute;\r
984 \r
985   for (Row = 0; Row < Private->DevNullRows; Row++) {\r
986     for (Column = 0; Column < Private->DevNullColumns; Column++, Screen++, Attributes++) {\r
987       *Screen     = ' ';\r
988       *Attributes = CurrentAttribute;\r
989     }\r
990     //\r
991     // Each line of the screen has a NULL on the end so we must skip over it\r
992     //\r
993     Screen++;\r
994   }\r
995 \r
996   DevNullTextOutSetCursorPosition (Private, 0, 0);\r
997 \r
998   return DevNullTextOutEnableCursor (Private, TRUE);\r
999 }\r
1000 \r
1001 EFI_STATUS\r
1002 DevNullTextOutSetCursorPosition (\r
1003   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private,\r
1004   IN  UINTN                           Column,\r
1005   IN  UINTN                           Row\r
1006   )\r
1007 /*++\r
1008 \r
1009   Routine Description:\r
1010     Sets the current coordinates of the cursor position\r
1011 \r
1012   Arguments:\r
1013     Private       - Protocol instance pointer.\r
1014     Column, Row - the position to set the cursor to. Must be greater than or\r
1015                   equal to zero and less than the number of columns and rows\r
1016                   by QueryMode ().\r
1017 \r
1018   Returns:\r
1019     EFI_SUCCESS      - The operation completed successfully.\r
1020     EFI_DEVICE_ERROR - The device had an error and\r
1021                        could not complete the request.\r
1022     EFI_UNSUPPORTED - The output device is not in a valid text mode, or the\r
1023                        cursor position is invalid for the current mode.\r
1024 \r
1025 --*/\r
1026 {\r
1027   //\r
1028   // No need to do extra check here as whether (Column, Row) is valid has\r
1029   // been checked in ConSplitterTextOutSetCursorPosition. And (0, 0) should\r
1030   // always be supported.\r
1031   //\r
1032   Private->TextOutMode.CursorColumn = (INT32) Column;\r
1033   Private->TextOutMode.CursorRow    = (INT32) Row;\r
1034 \r
1035   return EFI_SUCCESS;\r
1036 }\r
1037 \r
1038 EFI_STATUS\r
1039 DevNullTextOutEnableCursor (\r
1040   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private,\r
1041   IN  BOOLEAN                         Visible\r
1042   )\r
1043 /*++\r
1044   Routine Description:\r
1045 \r
1046     Implements SIMPLE_TEXT_OUTPUT.EnableCursor().\r
1047     In this driver, the cursor cannot be hidden.\r
1048 \r
1049   Arguments:\r
1050 \r
1051     Private - Indicates the calling context.\r
1052 \r
1053     Visible - If TRUE, the cursor is set to be visible, If FALSE, the cursor\r
1054               is set to be invisible.\r
1055 \r
1056   Returns:\r
1057 \r
1058     EFI_SUCCESS - The request is valid.\r
1059 \r
1060 \r
1061 --*/\r
1062 {\r
1063   Private->TextOutMode.CursorVisible = Visible;\r
1064 \r
1065   return EFI_SUCCESS;\r
1066 }\r
1067 \r
1068 EFI_STATUS\r
1069 DevNullSyncGopStdOut (\r
1070   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private\r
1071   )\r
1072 /*++\r
1073   Routine Description:\r
1074     Take the DevNull TextOut device and update the Simple Text Out on every\r
1075     UGA device.\r
1076 \r
1077   Arguments:\r
1078     Private - Indicates the calling context.\r
1079 \r
1080   Returns:\r
1081     EFI_SUCCESS - The request is valid.\r
1082     other       - Return status of TextOut->OutputString ()\r
1083 \r
1084 --*/\r
1085 {\r
1086   EFI_STATUS                       Status;\r
1087   EFI_STATUS                       ReturnStatus;\r
1088   UINTN                            Row;\r
1089   UINTN                            Column;\r
1090   UINTN                            List;\r
1091   UINTN                            MaxColumn;\r
1092   UINTN                            CurrentColumn;\r
1093   UINTN                            StartRow;\r
1094   UINTN                            StartColumn;\r
1095   INT32                            StartAttribute;\r
1096   BOOLEAN                          StartCursorState;\r
1097   CHAR16                           *Screen;\r
1098   CHAR16                           *Str;\r
1099   CHAR16                           *Buffer;\r
1100   CHAR16                           *BufferTail;\r
1101   CHAR16                           *ScreenStart;\r
1102   INT32                            CurrentAttribute;\r
1103   INT32                            *Attributes;\r
1104   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *Sto;\r
1105 \r
1106   //\r
1107   // Save the devices Attributes, Cursor enable state and location\r
1108   //\r
1109   StartColumn       = Private->TextOutMode.CursorColumn;\r
1110   StartRow          = Private->TextOutMode.CursorRow;\r
1111   StartAttribute    = Private->TextOutMode.Attribute;\r
1112   StartCursorState  = Private->TextOutMode.CursorVisible;\r
1113 \r
1114   for (List = 0; List < Private->CurrentNumberOfConsoles; List++) {\r
1115 \r
1116     Sto = Private->TextOutList[List].TextOut;\r
1117 \r
1118     //\r
1119     // Skip non GOP/UGA devices\r
1120     //\r
1121     if ((Private->TextOutList[List].GraphicsOutput != NULL) || (Private->TextOutList[List].UgaDraw != NULL)) {\r
1122       Sto->EnableCursor (Sto, FALSE);\r
1123       Sto->ClearScreen (Sto);\r
1124     }\r
1125   }\r
1126 \r
1127   ReturnStatus  = EFI_SUCCESS;\r
1128   Screen        = Private->DevNullScreen;\r
1129   Attributes    = Private->DevNullAttributes;\r
1130   MaxColumn     = Private->DevNullColumns;\r
1131 \r
1132   Buffer        = AllocateZeroPool ((MaxColumn + 1) * sizeof (CHAR16));\r
1133   if (Buffer == NULL) {\r
1134     return ReturnStatus;\r
1135   }\r
1136 \r
1137   for (Row = 0; Row < Private->DevNullRows; Row++, Screen += (MaxColumn + 1), Attributes += MaxColumn) {\r
1138 \r
1139     if (Row == (Private->DevNullRows - 1)) {\r
1140       //\r
1141       // Don't ever sync the last character as it will scroll the screen\r
1142       //\r
1143       Screen[MaxColumn - 1] = 0x00;\r
1144     }\r
1145 \r
1146     Column = 0;\r
1147     while (Column < MaxColumn) {\r
1148       if (Screen[Column]) {\r
1149         CurrentAttribute  = Attributes[Column];\r
1150         CurrentColumn     = Column;\r
1151         ScreenStart       = &Screen[Column];\r
1152 \r
1153         //\r
1154         // the line end is alway 0x0. So Column should be less than MaxColumn\r
1155         // It should be still in the same row\r
1156         //\r
1157         for (Str = ScreenStart, BufferTail = Buffer; *Str != 0; Str++, Column++) {\r
1158 \r
1159           if (Attributes[Column] != CurrentAttribute) {\r
1160             Column--;\r
1161             break;\r
1162           }\r
1163 \r
1164           *BufferTail = *Str;\r
1165           BufferTail++;\r
1166           if (Attributes[Column] & EFI_WIDE_ATTRIBUTE) {\r
1167             Str++;\r
1168             Column++;\r
1169           }\r
1170         }\r
1171 \r
1172         *BufferTail = 0;\r
1173 \r
1174         for (List = 0; List < Private->CurrentNumberOfConsoles; List++) {\r
1175 \r
1176           Sto = Private->TextOutList[List].TextOut;\r
1177 \r
1178           //\r
1179           // Skip non GOP/UGA devices\r
1180           //\r
1181           if ((Private->TextOutList[List].GraphicsOutput != NULL) || (Private->TextOutList[List].UgaDraw != NULL)) {\r
1182             Sto->SetAttribute (Sto, CurrentAttribute);\r
1183             Sto->SetCursorPosition (Sto, CurrentColumn, Row);\r
1184             Status = Sto->OutputString (Sto, Buffer);\r
1185             if (EFI_ERROR (Status)) {\r
1186               ReturnStatus = Status;\r
1187             }\r
1188           }\r
1189         }\r
1190 \r
1191       }\r
1192 \r
1193       Column++;\r
1194     }\r
1195   }\r
1196   //\r
1197   // Restore the devices Attributes, Cursor enable state and location\r
1198   //\r
1199   for (List = 0; List < Private->CurrentNumberOfConsoles; List++) {\r
1200     Sto = Private->TextOutList[List].TextOut;\r
1201 \r
1202     //\r
1203     // Skip non GOP/UGA devices\r
1204     //\r
1205     if ((Private->TextOutList[List].GraphicsOutput != NULL) || (Private->TextOutList[List].UgaDraw != NULL)) {\r
1206       Sto->SetAttribute (Sto, StartAttribute);\r
1207       Sto->SetCursorPosition (Sto, StartColumn, StartRow);\r
1208       Status = Sto->EnableCursor (Sto, StartCursorState);\r
1209       if (EFI_ERROR (Status)) {\r
1210         ReturnStatus = Status;\r
1211       }\r
1212     }\r
1213   }\r
1214 \r
1215   FreePool (Buffer);\r
1216 \r
1217   return ReturnStatus;\r
1218 }\r