git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1077 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1077 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*++
 | |
| 
 | |
| Copyright (c) 2006, Intel Corporation                                                         
 | |
| All rights reserved. This program and the accompanying materials                          
 | |
| are licensed and made available under the terms and conditions of the BSD License         
 | |
| which accompanies this distribution.  The full text of the license may be found at        
 | |
| http://opensource.org/licenses/bsd-license.php                                            
 | |
|                                                                                           
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
 | |
| 
 | |
| Module Name:
 | |
|   
 | |
|   ConSplitterGraphics.c
 | |
| 
 | |
| Abstract:
 | |
| 
 | |
|   Support for ConsoleControl protocol. Support for UGA Draw spliter.
 | |
|   Support for DevNull Console Out. This console uses memory buffers
 | |
|   to represnt the console. It allows a console to start very early and
 | |
|   when a new console is added it is synced up with the current console
 | |
| 
 | |
| --*/
 | |
| 
 | |
| 
 | |
| #include "ConSplitter.h"
 | |
| 
 | |
| static CHAR16 mCrLfString[3] = { CHAR_CARRIAGE_RETURN, CHAR_LINEFEED, CHAR_NULL };
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSpliterConsoleControlGetMode (
 | |
|   IN  EFI_CONSOLE_CONTROL_PROTOCOL    *This,
 | |
|   OUT EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode,
 | |
|   OUT BOOLEAN                         *UgaExists,
 | |
|   OUT BOOLEAN                         *StdInLocked
 | |
|   )
 | |
| /*++
 | |
| 
 | |
|   Routine Description:
 | |
|     Return the current video mode information. Also returns info about existence
 | |
|     of UGA Draw devices in system, and if the Std In device is locked. All the
 | |
|     arguments are optional and only returned if a non NULL pointer is passed in.
 | |
| 
 | |
|   Arguments:
 | |
|     This - Protocol instance pointer.
 | |
|     Mode        - Are we in text of grahics mode.
 | |
|     UgaExists   - TRUE if UGA Spliter has found a UGA device
 | |
|     StdInLocked - TRUE if StdIn device is keyboard locked
 | |
| 
 | |
|   Returns:
 | |
|     EFI_SUCCESS - Mode information returned.
 | |
|     EFI_INVALID_PARAMETER - Invalid parameters.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;
 | |
|   UINTN                           Index;
 | |
| 
 | |
|   Private = CONSOLE_CONTROL_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   if (Mode == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   *Mode = Private->UgaMode;
 | |
| 
 | |
|   if (UgaExists != NULL) {
 | |
|     *UgaExists = FALSE;
 | |
|     for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {
 | |
|       if (Private->TextOutList[Index].UgaDraw != NULL) {
 | |
|         *UgaExists = TRUE;
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (StdInLocked != NULL) {
 | |
|     *StdInLocked = ConSpliterConssoleControlStdInLocked ();
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSpliterConsoleControlSetMode (
 | |
|   IN  EFI_CONSOLE_CONTROL_PROTOCOL    *This,
 | |
|   IN  EFI_CONSOLE_CONTROL_SCREEN_MODE Mode
 | |
|   )
 | |
| /*++
 | |
| 
 | |
|   Routine Description:
 | |
|     Set the current mode to either text or graphics. Graphics is
 | |
|     for Quiet Boot.
 | |
| 
 | |
|   Arguments:
 | |
|     This  - Protocol instance pointer.
 | |
|     Mode  - Mode to set the 
 | |
| 
 | |
|   Returns:
 | |
|     EFI_SUCCESS     - Mode information returned.
 | |
|     EFI_INVALID_PARAMETER - Invalid parameter.
 | |
|     EFI_UNSUPPORTED - Operation unsupported.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;
 | |
|   UINTN                           Index;
 | |
|   TEXT_OUT_AND_UGA_DATA           *TextAndUga;
 | |
|   BOOLEAN                         Supported;
 | |
| 
 | |
|   Private = CONSOLE_CONTROL_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   if (Mode >= EfiConsoleControlScreenMaxValue) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Supported   = FALSE;
 | |
|   TextAndUga  = &Private->TextOutList[0];
 | |
|   for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++, TextAndUga++) {
 | |
|     if (TextAndUga->UgaDraw != NULL) {
 | |
|       Supported = TRUE;
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if ((!Supported) && (Mode == EfiConsoleControlScreenGraphics)) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   Private->UgaMode  = Mode;
 | |
| 
 | |
|   TextAndUga        = &Private->TextOutList[0];
 | |
|   for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++, TextAndUga++) {
 | |
| 
 | |
|     TextAndUga->TextOutEnabled = TRUE;
 | |
|     //
 | |
|     // If we are going into Graphics mode disable ConOut to any UGA device
 | |
|     //
 | |
|     if ((Mode == EfiConsoleControlScreenGraphics) && (TextAndUga->UgaDraw != NULL)) {
 | |
|       TextAndUga->TextOutEnabled = FALSE;
 | |
|       DevNullUgaSync (Private, TextAndUga->UgaDraw);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (Mode == EfiConsoleControlScreenText) {
 | |
|     DevNullSyncUgaStdOut (Private);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSpliterUgaDrawGetMode (
 | |
|   IN  EFI_UGA_DRAW_PROTOCOL           *This,
 | |
|   OUT UINT32                          *HorizontalResolution,
 | |
|   OUT UINT32                          *VerticalResolution,
 | |
|   OUT UINT32                          *ColorDepth,
 | |
|   OUT UINT32                          *RefreshRate
 | |
|   )
 | |
| /*++
 | |
| 
 | |
|   Routine Description:
 | |
|     Return the current video mode information.
 | |
| 
 | |
|   Arguments:
 | |
|     This                  - Protocol instance pointer.
 | |
|     HorizontalResolution  - Current video horizontal resolution in pixels
 | |
|     VerticalResolution    - Current video vertical resolution in pixels
 | |
|     ColorDepth            - Current video color depth in bits per pixel
 | |
|     RefreshRate           - Current video refresh rate in Hz.
 | |
| 
 | |
|   Returns:
 | |
|     EFI_SUCCESS           - Mode information returned.
 | |
|     EFI_NOT_STARTED       - Video display is not initialized. Call SetMode () 
 | |
|     EFI_INVALID_PARAMETER - One of the input args was NULL.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;
 | |
| 
 | |
|   if (!(HorizontalResolution && VerticalResolution && RefreshRate && ColorDepth)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   //
 | |
|   // retrieve private data
 | |
|   //
 | |
|   Private               = UGA_DRAW_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   *HorizontalResolution = Private->UgaHorizontalResolution;
 | |
|   *VerticalResolution   = Private->UgaVerticalResolution;
 | |
|   *ColorDepth           = Private->UgaColorDepth;
 | |
|   *RefreshRate          = Private->UgaRefreshRate;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSpliterUgaDrawSetMode (
 | |
|   IN  EFI_UGA_DRAW_PROTOCOL           *This,
 | |
|   IN UINT32                           HorizontalResolution,
 | |
|   IN UINT32                           VerticalResolution,
 | |
|   IN UINT32                           ColorDepth,
 | |
|   IN UINT32                           RefreshRate
 | |
|   )
 | |
| /*++
 | |
| 
 | |
|   Routine Description:
 | |
|     Return the current video mode information.
 | |
| 
 | |
|   Arguments:
 | |
|     This                  - Protocol instance pointer.
 | |
|     HorizontalResolution  - Current video horizontal resolution in pixels
 | |
|     VerticalResolution    - Current video vertical resolution in pixels
 | |
|     ColorDepth            - Current video color depth in bits per pixel
 | |
|     RefreshRate           - Current video refresh rate in Hz.
 | |
| 
 | |
|   Returns:
 | |
|     EFI_SUCCESS     - Mode information returned.
 | |
|     EFI_NOT_STARTED - Video display is not initialized. Call SetMode () 
 | |
|     EFI_OUT_OF_RESOURCES - Out of resources.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS                      Status;
 | |
|   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;
 | |
|   UINTN                           Index;
 | |
|   EFI_STATUS                      ReturnStatus;
 | |
|   UINTN                           Size;
 | |
| 
 | |
|   Private = UGA_DRAW_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   //
 | |
|   // UgaDevNullSetMode ()
 | |
|   //
 | |
|   ReturnStatus = EFI_SUCCESS;
 | |
| 
 | |
|   //
 | |
|   // Free the old version
 | |
|   //
 | |
|   gBS->FreePool (Private->UgaBlt);
 | |
| 
 | |
|   //
 | |
|   // Allocate the virtual Blt buffer
 | |
|   //
 | |
|   Size            = HorizontalResolution * VerticalResolution * sizeof (EFI_UGA_PIXEL);
 | |
|   Private->UgaBlt = AllocateZeroPool (Size);
 | |
|   if (Private->UgaBlt == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Update the Mode data
 | |
|   //
 | |
|   Private->UgaHorizontalResolution  = HorizontalResolution;
 | |
|   Private->UgaVerticalResolution    = VerticalResolution;
 | |
|   Private->UgaColorDepth            = ColorDepth;
 | |
|   Private->UgaRefreshRate           = RefreshRate;
 | |
| 
 | |
|   if (Private->UgaMode != EfiConsoleControlScreenGraphics) {
 | |
|     return ReturnStatus;
 | |
|   }
 | |
|   //
 | |
|   // return the worst status met
 | |
|   //
 | |
|   for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {
 | |
|     if (Private->TextOutList[Index].UgaDraw != NULL) {
 | |
|       Status = Private->TextOutList[Index].UgaDraw->SetMode (
 | |
|                                                       Private->TextOutList[Index].UgaDraw,
 | |
|                                                       HorizontalResolution,
 | |
|                                                       VerticalResolution,
 | |
|                                                       ColorDepth,
 | |
|                                                       RefreshRate
 | |
|                                                       );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         ReturnStatus = Status;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return ReturnStatus;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| DevNullUgaBlt (
 | |
|   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA                *Private,
 | |
|   IN  EFI_UGA_PIXEL                                 *BltBuffer, OPTIONAL
 | |
|   IN  EFI_UGA_BLT_OPERATION                         BltOperation,
 | |
|   IN  UINTN                                         SourceX,
 | |
|   IN  UINTN                                         SourceY,
 | |
|   IN  UINTN                                         DestinationX,
 | |
|   IN  UINTN                                         DestinationY,
 | |
|   IN  UINTN                                         Width,
 | |
|   IN  UINTN                                         Height,
 | |
|   IN  UINTN                                         Delta         OPTIONAL
 | |
|   )
 | |
| {
 | |
|   UINTN         SrcY;
 | |
|   UINTN         Index;
 | |
|   EFI_UGA_PIXEL *BltPtr;
 | |
|   EFI_UGA_PIXEL *ScreenPtr;
 | |
|   UINT32        HorizontalResolution;
 | |
|   UINT32        VerticalResolution;
 | |
| 
 | |
|   if ((BltOperation < 0) || (BltOperation >= EfiUgaBltMax)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (Width == 0 || Height == 0) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (Delta == 0) {
 | |
|     Delta = Width * sizeof (EFI_UGA_PIXEL);
 | |
|   }
 | |
| 
 | |
|   HorizontalResolution  = Private->UgaHorizontalResolution;
 | |
|   VerticalResolution    = Private->UgaVerticalResolution;
 | |
| 
 | |
|   //
 | |
|   // We need to fill the Virtual Screen buffer with the blt data.
 | |
|   //
 | |
|   if (BltOperation == EfiUgaVideoToBltBuffer) {
 | |
|     //
 | |
|     // Video to BltBuffer: Source is Video, destination is BltBuffer
 | |
|     //
 | |
|     if ((SourceY + Height) > VerticalResolution) {
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
| 
 | |
|     if ((SourceX + Width) > HorizontalResolution) {
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
| 
 | |
|     BltPtr    = (EFI_UGA_PIXEL *) ((UINT8 *) BltBuffer + DestinationY * Delta + DestinationX * sizeof (EFI_UGA_PIXEL));
 | |
|     ScreenPtr = &Private->UgaBlt[SourceY * HorizontalResolution + SourceX];
 | |
|     while (Height) {
 | |
|       CopyMem (BltPtr, ScreenPtr, Width * sizeof (EFI_UGA_PIXEL));
 | |
|       BltPtr = (EFI_UGA_PIXEL *) ((UINT8 *) BltPtr + Delta);
 | |
|       ScreenPtr += HorizontalResolution;
 | |
|       Height--;
 | |
|     }
 | |
|   } else {
 | |
|     //
 | |
|     // BltBuffer to Video: Source is BltBuffer, destination is Video
 | |
|     //
 | |
|     if (DestinationY + Height > VerticalResolution) {
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
| 
 | |
|     if (DestinationX + Width > HorizontalResolution) {
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
| 
 | |
|     ScreenPtr = &Private->UgaBlt[DestinationY * HorizontalResolution + DestinationX];
 | |
|     SrcY      = SourceY;
 | |
|     while (Height) {
 | |
|       if (BltOperation == EfiUgaVideoFill) {
 | |
|         for (Index = 0; Index < Width; Index++) {
 | |
|           ScreenPtr[Index] = *BltBuffer;
 | |
|         }
 | |
|       } else {
 | |
|         if (BltOperation == EfiUgaBltBufferToVideo) {
 | |
|           BltPtr = (EFI_UGA_PIXEL *) ((UINT8 *) BltBuffer + SrcY * Delta + SourceX * sizeof (EFI_UGA_PIXEL));
 | |
|         } else {
 | |
|           BltPtr = &Private->UgaBlt[SrcY * HorizontalResolution + SourceX];
 | |
|         }
 | |
| 
 | |
|         CopyMem (ScreenPtr, BltPtr, Width * sizeof (EFI_UGA_PIXEL));
 | |
|       }
 | |
| 
 | |
|       ScreenPtr += HorizontalResolution;
 | |
|       SrcY++;
 | |
|       Height--;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ConSpliterUgaDrawBlt (
 | |
|   IN  EFI_UGA_DRAW_PROTOCOL                         *This,
 | |
|   IN  EFI_UGA_PIXEL                                 *BltBuffer, OPTIONAL
 | |
|   IN  EFI_UGA_BLT_OPERATION                         BltOperation,
 | |
|   IN  UINTN                                         SourceX,
 | |
|   IN  UINTN                                         SourceY,
 | |
|   IN  UINTN                                         DestinationX,
 | |
|   IN  UINTN                                         DestinationY,
 | |
|   IN  UINTN                                         Width,
 | |
|   IN  UINTN                                         Height,
 | |
|   IN  UINTN                                         Delta         OPTIONAL
 | |
|   )
 | |
| /*++
 | |
| 
 | |
|   Routine Description:
 | |
|     The following table defines actions for BltOperations:
 | |
|     EfiUgaVideoFill - Write data from the  BltBuffer pixel (SourceX, SourceY) 
 | |
|       directly to every pixel of the video display rectangle 
 | |
|       (DestinationX, DestinationY) 
 | |
|       (DestinationX + Width, DestinationY + Height).
 | |
|       Only one pixel will be used from the BltBuffer. Delta is NOT used.
 | |
|     EfiUgaVideoToBltBuffer - Read data from the video display rectangle 
 | |
|       (SourceX, SourceY) (SourceX + Width, SourceY + Height) and place it in 
 | |
|       the BltBuffer rectangle (DestinationX, DestinationY ) 
 | |
|       (DestinationX + Width, DestinationY + Height). If DestinationX or 
 | |
|       DestinationY is not zero then Delta must be set to the length in bytes 
 | |
|       of a row in the BltBuffer.
 | |
|     EfiUgaBltBufferToVideo - Write data from the  BltBuffer rectangle 
 | |
|       (SourceX, SourceY) (SourceX + Width, SourceY + Height) directly to the 
 | |
|       video display rectangle (DestinationX, DestinationY) 
 | |
|       (DestinationX + Width, DestinationY + Height). If SourceX or SourceY is 
 | |
|       not zero then Delta must be set to the length in bytes of a row in the 
 | |
|       BltBuffer.
 | |
|     EfiUgaVideoToVideo - Copy from the video display rectangle 
 | |
|       (SourceX, SourceY) (SourceX + Width, SourceY + Height) .
 | |
|       to the video display rectangle (DestinationX, DestinationY) 
 | |
|       (DestinationX + Width, DestinationY + Height). 
 | |
|      The BltBuffer and Delta  are not used in this mode.
 | |
| 
 | |
|   Arguments:
 | |
|     This          - Protocol instance pointer.
 | |
|     BltBuffer     - Buffer containing data to blit into video buffer. This 
 | |
|                     buffer has a size of Width*Height*sizeof(EFI_UGA_PIXEL)
 | |
|     BltOperation  - Operation to perform on BlitBuffer and video memory
 | |
|     SourceX       - X coordinate of source for the BltBuffer.
 | |
|     SourceY       - Y coordinate of source for the BltBuffer.
 | |
|     DestinationX  - X coordinate of destination for the BltBuffer.
 | |
|     DestinationY  - Y coordinate of destination for the BltBuffer.
 | |
|     Width         - Width of rectangle in BltBuffer in pixels.
 | |
|     Height        - Hight of rectangle in BltBuffer in pixels.
 | |
|     Delta         -
 | |
|   
 | |
|   Returns:
 | |
|     EFI_SUCCESS           - The Blt operation completed.
 | |
|     EFI_INVALID_PARAMETER - BltOperation is not valid.
 | |
|     EFI_DEVICE_ERROR      - A hardware error occured writting to the video 
 | |
|                              buffer.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS                      Status;
 | |
|   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;
 | |
|   UINTN                           Index;
 | |
|   EFI_STATUS                      ReturnStatus;
 | |
| 
 | |
|   Private = UGA_DRAW_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
 | |
| 
 | |
|   //
 | |
|   // Sync up DevNull UGA device
 | |
|   //
 | |
|   ReturnStatus = DevNullUgaBlt (
 | |
|                   Private,
 | |
|                   BltBuffer,
 | |
|                   BltOperation,
 | |
|                   SourceX,
 | |
|                   SourceY,
 | |
|                   DestinationX,
 | |
|                   DestinationY,
 | |
|                   Width,
 | |
|                   Height,
 | |
|                   Delta
 | |
|                   );
 | |
|   if (Private->UgaMode != EfiConsoleControlScreenGraphics) {
 | |
|     return ReturnStatus;
 | |
|   }
 | |
|   //
 | |
|   // return the worst status met
 | |
|   //
 | |
|   for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {
 | |
|     if (Private->TextOutList[Index].UgaDraw != NULL) {
 | |
|       Status = Private->TextOutList[Index].UgaDraw->Blt (
 | |
|                                                       Private->TextOutList[Index].UgaDraw,
 | |
|                                                       BltBuffer,
 | |
|                                                       BltOperation,
 | |
|                                                       SourceX,
 | |
|                                                       SourceY,
 | |
|                                                       DestinationX,
 | |
|                                                       DestinationY,
 | |
|                                                       Width,
 | |
|                                                       Height,
 | |
|                                                       Delta
 | |
|                                                       );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         ReturnStatus = Status;
 | |
|       } else if (BltOperation == EfiUgaVideoToBltBuffer) {
 | |
|         //
 | |
|         // Only need to read the data into buffer one time
 | |
|         //
 | |
|         return EFI_SUCCESS;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return ReturnStatus;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| DevNullUgaSync (
 | |
|   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private,
 | |
|   IN  EFI_UGA_DRAW_PROTOCOL           *UgaDraw
 | |
|   )
 | |
| {
 | |
|   return UgaDraw->Blt (
 | |
|                     UgaDraw,
 | |
|                     Private->UgaBlt,
 | |
|                     EfiUgaBltBufferToVideo,
 | |
|                     0,
 | |
|                     0,
 | |
|                     0,
 | |
|                     0,
 | |
|                     Private->UgaHorizontalResolution,
 | |
|                     Private->UgaVerticalResolution,
 | |
|                     Private->UgaHorizontalResolution * sizeof (EFI_UGA_PIXEL)
 | |
|                     );
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| DevNullTextOutOutputString (
 | |
|   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private,
 | |
|   IN  CHAR16                          *WString
 | |
|   )
 | |
| /*++
 | |
| 
 | |
|   Routine Description:
 | |
|     Write a Unicode string to the output device.
 | |
| 
 | |
|   Arguments:
 | |
|     Private - Pointer to the console output splitter's private data. It
 | |
|               indicates the calling context.
 | |
|     WString - The NULL-terminated Unicode string to be displayed on the output
 | |
|               device(s). All output devices must also support the Unicode 
 | |
|               drawing defined in this file.
 | |
| 
 | |
|   Returns:
 | |
|     EFI_SUCCESS            - The string was output to the device.
 | |
|     EFI_DEVICE_ERROR       - The device reported an error while attempting to 
 | |
|                               output the text.
 | |
|     EFI_UNSUPPORTED        - The output device's mode is not currently in a 
 | |
|                               defined text mode.
 | |
|     EFI_WARN_UNKNOWN_GLYPH - This warning code indicates that some of the 
 | |
|                               characters in the Unicode string could not be 
 | |
|                               rendered and were skipped.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINTN                       SizeScreen;
 | |
|   UINTN                       SizeAttribute;
 | |
|   UINTN                       Index;
 | |
|   EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
 | |
|   CHAR16                      *Screen;
 | |
|   CHAR16                      *NullScreen;
 | |
|   CHAR16                      InsertChar;
 | |
|   CHAR16                      TempChar;
 | |
|   CHAR16                      *PStr;
 | |
|   INT32                       *Attribute;
 | |
|   INT32                       *NullAttributes;
 | |
|   INT32                       CurrentWidth;
 | |
|   UINTN                       LastRow;
 | |
|   UINTN                       MaxColumn;
 | |
| 
 | |
|   Mode            = &Private->TextOutMode;
 | |
|   NullScreen      = Private->DevNullScreen;
 | |
|   NullAttributes  = Private->DevNullAttributes;
 | |
|   LastRow         = Private->DevNullRows - 1;
 | |
|   MaxColumn       = Private->DevNullColumns;
 | |
| 
 | |
|   if (Mode->Attribute & EFI_WIDE_ATTRIBUTE) {
 | |
|     CurrentWidth = 2;
 | |
|   } else {
 | |
|     CurrentWidth = 1;
 | |
|   }
 | |
| 
 | |
|   while (*WString) {
 | |
| 
 | |
|     if (*WString == CHAR_BACKSPACE) {
 | |
|       //
 | |
|       // If the cursor is at the left edge of the display, then move the cursor
 | |
|       // one row up.
 | |
|       //
 | |
|       if (Mode->CursorColumn == 0 && Mode->CursorRow > 0) {
 | |
|         Mode->CursorRow--;
 | |
|         Mode->CursorColumn = (INT32) MaxColumn;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // If the cursor is not at the left edge of the display,
 | |
|       // then move the cursor left one column.
 | |
|       //
 | |
|       if (Mode->CursorColumn > 0) {
 | |
|         Mode->CursorColumn--;
 | |
|         if (Mode->CursorColumn > 0 &&
 | |
|             NullAttributes[Mode->CursorRow * MaxColumn + Mode->CursorColumn - 1] & EFI_WIDE_ATTRIBUTE
 | |
|             ) {
 | |
|           Mode->CursorColumn--;
 | |
| 
 | |
|           //
 | |
|           // Insert an extra backspace
 | |
|           //
 | |
|           InsertChar  = CHAR_BACKSPACE;
 | |
|           PStr        = WString + 1;
 | |
|           while (*PStr) {
 | |
|             TempChar    = *PStr;
 | |
|             *PStr       = InsertChar;
 | |
|             InsertChar  = TempChar;
 | |
|             PStr++;
 | |
|           }
 | |
| 
 | |
|           *PStr     = InsertChar;
 | |
|           *(++PStr) = 0;
 | |
| 
 | |
|           WString++;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       WString++;
 | |
| 
 | |
|     } else if (*WString == CHAR_LINEFEED) {
 | |
|       //
 | |
|       // If the cursor is at the bottom of the display,
 | |
|       // then scroll the display one row, and do not update
 | |
|       // the cursor position. Otherwise, move the cursor down one row.
 | |
|       //
 | |
|       if (Mode->CursorRow == (INT32) (LastRow)) {
 | |
|         //
 | |
|         // Scroll Screen Up One Row
 | |
|         //
 | |
|         SizeAttribute = LastRow * MaxColumn;
 | |
|         CopyMem (
 | |
|           NullAttributes,
 | |
|           NullAttributes + MaxColumn,
 | |
|           SizeAttribute * sizeof (INT32)
 | |
|           );
 | |
| 
 | |
|         //
 | |
|         // Each row has an ending CHAR_NULL. So one more character each line
 | |
|         // for DevNullScreen than DevNullAttributes
 | |
|         //
 | |
|         SizeScreen = SizeAttribute + LastRow;
 | |
|         CopyMem (
 | |
|           NullScreen,
 | |
|           NullScreen + (MaxColumn + 1),
 | |
|           SizeScreen * sizeof (CHAR16)
 | |
|           );
 | |
| 
 | |
|         //
 | |
|         // Print Blank Line at last line
 | |
|         //
 | |
|         Screen    = NullScreen + SizeScreen;
 | |
|         Attribute = NullAttributes + SizeAttribute;
 | |
| 
 | |
|         for (Index = 0; Index < MaxColumn; Index++, Screen++, Attribute++) {
 | |
|           *Screen     = ' ';
 | |
|           *Attribute  = Mode->Attribute;
 | |
|         }
 | |
|       } else {
 | |
|         Mode->CursorRow++;
 | |
|       }
 | |
| 
 | |
|       WString++;
 | |
|     } else if (*WString == CHAR_CARRIAGE_RETURN) {
 | |
|       //
 | |
|       // Move the cursor to the beginning of the current row.
 | |
|       //
 | |
|       Mode->CursorColumn = 0;
 | |
|       WString++;
 | |
|     } else {
 | |
|       //
 | |
|       // Print the character at the current cursor position and
 | |
|       // move the cursor right one column. If this moves the cursor
 | |
|       // past the right edge of the display, then the line should wrap to
 | |
|       // the beginning of the next line. This is equivalent to inserting
 | |
|       // a CR and an LF. Note that if the cursor is at the bottom of the
 | |
|       // display, and the line wraps, then the display will be scrolled
 | |
|       // one line.
 | |
|       //
 | |
|       Index = Mode->CursorRow * MaxColumn + Mode->CursorColumn;
 | |
| 
 | |
|       while (Mode->CursorColumn < (INT32) MaxColumn) {
 | |
|         if (*WString == CHAR_NULL) {
 | |
|           break;
 | |
|         }
 | |
| 
 | |
|         if (*WString == CHAR_BACKSPACE) {
 | |
|           break;
 | |
|         }
 | |
| 
 | |
|         if (*WString == CHAR_LINEFEED) {
 | |
|           break;
 | |
|         }
 | |
| 
 | |
|         if (*WString == CHAR_CARRIAGE_RETURN) {
 | |
|           break;
 | |
|         }
 | |
| 
 | |
|         if (*WString == WIDE_CHAR || *WString == NARROW_CHAR) {
 | |
|           CurrentWidth = (*WString == WIDE_CHAR) ? 2 : 1;
 | |
|           WString++;
 | |
|           continue;
 | |
|         }
 | |
| 
 | |
|         if (Mode->CursorColumn + CurrentWidth > (INT32) MaxColumn) {
 | |
|           //
 | |
|           // If a wide char is at the rightmost column, then move the char
 | |
|           // to the beginning of the next row
 | |
|           //
 | |
|           NullScreen[Index + Mode->CursorRow] = L' ';
 | |
|           NullAttributes[Index]               = Mode->Attribute | (UINT32) EFI_WIDE_ATTRIBUTE;
 | |
|           Index++;
 | |
|           Mode->CursorColumn++;
 | |
|         } else {
 | |
|           NullScreen[Index + Mode->CursorRow] = *WString;
 | |
|           NullAttributes[Index]               = Mode->Attribute;
 | |
|           if (CurrentWidth == 1) {
 | |
|             NullAttributes[Index] &= (~ (UINT32) EFI_WIDE_ATTRIBUTE);
 | |
|           } else {
 | |
|             NullAttributes[Index] |= (UINT32) EFI_WIDE_ATTRIBUTE;
 | |
|             NullAttributes[Index + 1] &= (~ (UINT32) EFI_WIDE_ATTRIBUTE);
 | |
|           }
 | |
| 
 | |
|           Index += CurrentWidth;
 | |
|           WString++;
 | |
|           Mode->CursorColumn += CurrentWidth;
 | |
|         }
 | |
|       }
 | |
|       //
 | |
|       // At the end of line, output carriage return and line feed
 | |
|       //
 | |
|       if (Mode->CursorColumn >= (INT32) MaxColumn) {
 | |
|         DevNullTextOutOutputString (Private, mCrLfString);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| DevNullTextOutSetMode (
 | |
|   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private,
 | |
|   IN  UINTN                           ModeNumber
 | |
|   )
 | |
| /*++
 | |
| 
 | |
|   Routine Description:
 | |
|     Sets the output device(s) to a specified mode.
 | |
| 
 | |
|   Arguments:
 | |
|     Private    - Private data structure pointer.
 | |
|     ModeNumber - The mode number to set.
 | |
| 
 | |
|   Returns:
 | |
|     EFI_SUCCESS      - The requested text mode was set.
 | |
|     EFI_DEVICE_ERROR - The device had an error and 
 | |
|                        could not complete the request.
 | |
|     EFI_UNSUPPORTED - The mode number was not valid.
 | |
|     EFI_OUT_OF_RESOURCES - Out of resources.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINTN                         Size;
 | |
|   UINTN                         Row;
 | |
|   UINTN                         Column;
 | |
|   TEXT_OUT_SPLITTER_QUERY_DATA  *Mode;
 | |
| 
 | |
|   //
 | |
|   // No extra check for ModeNumber here, as it has been checked in
 | |
|   // ConSplitterTextOutSetMode. And mode 0 should always be supported.
 | |
|   //
 | |
|   Mode    = &(Private->TextOutQueryData[ModeNumber]);
 | |
|   Row     = Mode->Rows;
 | |
|   Column  = Mode->Columns;
 | |
| 
 | |
|   if (Row <= 0 && Column <= 0) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   if (Private->DevNullColumns != Column || Private->DevNullRows != Row) {
 | |
| 
 | |
|     Private->TextOutMode.Mode = (INT32) ModeNumber;
 | |
|     Private->DevNullColumns   = Column;
 | |
|     Private->DevNullRows      = Row;
 | |
| 
 | |
|     gBS->FreePool (Private->DevNullScreen);
 | |
| 
 | |
|     Size                    = (Row * (Column + 1)) * sizeof (CHAR16);
 | |
|     Private->DevNullScreen  = AllocateZeroPool (Size);
 | |
|     if (Private->DevNullScreen == NULL) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
| 
 | |
|     gBS->FreePool (Private->DevNullAttributes);
 | |
| 
 | |
|     Size                        = Row * Column * sizeof (INT32);
 | |
|     Private->DevNullAttributes  = AllocateZeroPool (Size);
 | |
|     if (Private->DevNullAttributes == NULL) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   DevNullTextOutClearScreen (Private);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| DevNullTextOutClearScreen (
 | |
|   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private
 | |
|   )
 | |
| /*++
 | |
| 
 | |
|   Routine Description:
 | |
|     Clears the output device(s) display to the currently selected background 
 | |
|     color.
 | |
| 
 | |
|   Arguments:
 | |
|     Private     - Protocol instance pointer.
 | |
| 
 | |
|   Returns:
 | |
|     EFI_SUCCESS      - The operation completed successfully.
 | |
|     EFI_DEVICE_ERROR - The device had an error and 
 | |
|                        could not complete the request.
 | |
|     EFI_UNSUPPORTED - The output device is not in a valid text mode.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINTN   Row;
 | |
|   UINTN   Column;
 | |
|   CHAR16  *Screen;
 | |
|   INT32   *Attributes;
 | |
|   INT32   CurrentAttribute;
 | |
| 
 | |
|   //
 | |
|   // Clear the DevNull Text Out Buffers.
 | |
|   // The screen is filled with spaces.
 | |
|   // The attributes are all synced with the current Simple Text Out Attribute
 | |
|   //
 | |
|   Screen            = Private->DevNullScreen;
 | |
|   Attributes        = Private->DevNullAttributes;
 | |
|   CurrentAttribute  = Private->TextOutMode.Attribute;
 | |
| 
 | |
|   for (Row = 0; Row < Private->DevNullRows; Row++) {
 | |
|     for (Column = 0; Column < Private->DevNullColumns; Column++, Screen++, Attributes++) {
 | |
|       *Screen     = ' ';
 | |
|       *Attributes = CurrentAttribute;
 | |
|     }
 | |
|     //
 | |
|     // Each line of the screen has a NULL on the end so we must skip over it
 | |
|     //
 | |
|     Screen++;
 | |
|   }
 | |
| 
 | |
|   DevNullTextOutSetCursorPosition (Private, 0, 0);
 | |
| 
 | |
|   return DevNullTextOutEnableCursor (Private, TRUE);
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| DevNullTextOutSetCursorPosition (
 | |
|   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private,
 | |
|   IN  UINTN                           Column,
 | |
|   IN  UINTN                           Row
 | |
|   )
 | |
| /*++
 | |
| 
 | |
|   Routine Description:
 | |
|     Sets the current coordinates of the cursor position
 | |
| 
 | |
|   Arguments:
 | |
|     Private       - Protocol instance pointer.
 | |
|     Column, Row - the position to set the cursor to. Must be greater than or
 | |
|                   equal to zero and less than the number of columns and rows
 | |
|                   by QueryMode ().
 | |
| 
 | |
|   Returns:
 | |
|     EFI_SUCCESS      - The operation completed successfully.
 | |
|     EFI_DEVICE_ERROR - The device had an error and 
 | |
|                        could not complete the request.
 | |
|     EFI_UNSUPPORTED - The output device is not in a valid text mode, or the 
 | |
|                        cursor position is invalid for the current mode.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   //
 | |
|   // No need to do extra check here as whether (Column, Row) is valid has
 | |
|   // been checked in ConSplitterTextOutSetCursorPosition. And (0, 0) should
 | |
|   // always be supported.
 | |
|   //
 | |
|   Private->TextOutMode.CursorColumn = (INT32) Column;
 | |
|   Private->TextOutMode.CursorRow    = (INT32) Row;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| DevNullTextOutEnableCursor (
 | |
|   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private,
 | |
|   IN  BOOLEAN                         Visible
 | |
|   )
 | |
| /*++
 | |
|   Routine Description:
 | |
|   
 | |
|     Implements SIMPLE_TEXT_OUTPUT.EnableCursor().
 | |
|     In this driver, the cursor cannot be hidden.        
 | |
|   
 | |
|   Arguments:
 | |
|   
 | |
|     Private - Indicates the calling context.
 | |
|         
 | |
|     Visible - If TRUE, the cursor is set to be visible, If FALSE, the cursor 
 | |
|               is set to be invisible.        
 | |
| 
 | |
|   Returns:
 | |
|   
 | |
|     EFI_SUCCESS - The request is valid.
 | |
|        
 | |
|                
 | |
| --*/
 | |
| {
 | |
|   Private->TextOutMode.CursorVisible = Visible;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| DevNullSyncUgaStdOut (
 | |
|   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private
 | |
|   )
 | |
| /*++
 | |
|   Routine Description:
 | |
|     Take the DevNull TextOut device and update the Simple Text Out on every
 | |
|     UGA device. 
 | |
|  
 | |
|   Arguments:
 | |
|     Private - Indicates the calling context.
 | |
| 
 | |
|   Returns:
 | |
|     EFI_SUCCESS - The request is valid.
 | |
|     other       - Return status of TextOut->OutputString ()
 | |
|                
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS                    Status;
 | |
|   EFI_STATUS                    ReturnStatus;
 | |
|   UINTN                         Row;
 | |
|   UINTN                         Column;
 | |
|   UINTN                         List;
 | |
|   UINTN                         MaxColumn;
 | |
|   UINTN                         CurrentColumn;
 | |
|   UINTN                         StartRow;
 | |
|   UINTN                         StartColumn;
 | |
|   INT32                         StartAttribute;
 | |
|   BOOLEAN                       StartCursorState;
 | |
|   CHAR16                        *Screen;
 | |
|   CHAR16                        *Str;
 | |
|   CHAR16                        *Buffer;
 | |
|   CHAR16                        *BufferTail;
 | |
|   CHAR16                        *ScreenStart;
 | |
|   INT32                         CurrentAttribute;
 | |
|   INT32                         *Attributes;
 | |
|   EFI_SIMPLE_TEXT_OUT_PROTOCOL  *Sto;
 | |
| 
 | |
|   //
 | |
|   // Save the devices Attributes, Cursor enable state and location
 | |
|   //
 | |
|   StartColumn       = Private->TextOutMode.CursorColumn;
 | |
|   StartRow          = Private->TextOutMode.CursorRow;
 | |
|   StartAttribute    = Private->TextOutMode.Attribute;
 | |
|   StartCursorState  = Private->TextOutMode.CursorVisible;
 | |
| 
 | |
|   for (List = 0; List < Private->CurrentNumberOfConsoles; List++) {
 | |
| 
 | |
|     Sto = Private->TextOutList[List].TextOut;
 | |
| 
 | |
|     //
 | |
|     // Skip non UGA devices
 | |
|     //
 | |
|     if (Private->TextOutList[List].UgaDraw != NULL) {
 | |
|       Sto->EnableCursor (Sto, FALSE);
 | |
|       Sto->ClearScreen (Sto);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   ReturnStatus  = EFI_SUCCESS;
 | |
|   Screen        = Private->DevNullScreen;
 | |
|   Attributes    = Private->DevNullAttributes;
 | |
|   MaxColumn     = Private->DevNullColumns;
 | |
| 
 | |
|   Buffer        = AllocateZeroPool ((MaxColumn + 1) * sizeof (CHAR16));
 | |
| 
 | |
|   for (Row = 0; Row < Private->DevNullRows; Row++, Screen += (MaxColumn + 1), Attributes += MaxColumn) {
 | |
| 
 | |
|     if (Row == (Private->DevNullRows - 1)) {
 | |
|       //
 | |
|       // Don't ever sync the last character as it will scroll the screen
 | |
|       //
 | |
|       Screen[MaxColumn - 1] = 0x00;
 | |
|     }
 | |
| 
 | |
|     Column = 0;
 | |
|     while (Column < MaxColumn) {
 | |
|       if (Screen[Column]) {
 | |
|         CurrentAttribute  = Attributes[Column];
 | |
|         CurrentColumn     = Column;
 | |
|         ScreenStart       = &Screen[Column];
 | |
| 
 | |
|         //
 | |
|         // the line end is alway 0x0. So Column should be less than MaxColumn
 | |
|         // It should be still in the same row
 | |
|         //
 | |
|         for (Str = ScreenStart, BufferTail = Buffer; *Str != 0; Str++, Column++) {
 | |
| 
 | |
|           if (Attributes[Column] != CurrentAttribute) {
 | |
|             Column--;
 | |
|             break;
 | |
|           }
 | |
| 
 | |
|           *BufferTail = *Str;
 | |
|           BufferTail++;
 | |
|           if (Attributes[Column] & EFI_WIDE_ATTRIBUTE) {
 | |
|             Str++;
 | |
|             Column++;
 | |
|           }
 | |
|         }
 | |
| 
 | |
|         *BufferTail = 0;
 | |
| 
 | |
|         for (List = 0; List < Private->CurrentNumberOfConsoles; List++) {
 | |
| 
 | |
|           Sto = Private->TextOutList[List].TextOut;
 | |
| 
 | |
|           //
 | |
|           // Skip non UGA devices
 | |
|           //
 | |
|           if (Private->TextOutList[List].UgaDraw != NULL) {
 | |
|             Sto->SetAttribute (Sto, CurrentAttribute);
 | |
|             Sto->SetCursorPosition (Sto, CurrentColumn, Row);
 | |
|             Status = Sto->OutputString (Sto, Buffer);
 | |
|             if (EFI_ERROR (Status)) {
 | |
|               ReturnStatus = Status;
 | |
|             }
 | |
|           }
 | |
|         }
 | |
| 
 | |
|       }
 | |
| 
 | |
|       Column++;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // Restore the devices Attributes, Cursor enable state and location
 | |
|   //
 | |
|   for (List = 0; List < Private->CurrentNumberOfConsoles; List++) {
 | |
|     Sto = Private->TextOutList[List].TextOut;
 | |
| 
 | |
|     //
 | |
|     // Skip non UGA devices
 | |
|     //
 | |
|     if (Private->TextOutList[List].UgaDraw != NULL) {
 | |
|       Sto->SetAttribute (Sto, StartAttribute);
 | |
|       Sto->SetCursorPosition (Sto, StartColumn, StartRow);
 | |
|       Status = Sto->EnableCursor (Sto, StartCursorState);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         ReturnStatus = Status;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   gBS->FreePool (Buffer);
 | |
| 
 | |
|   return ReturnStatus;
 | |
| }
 |