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