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
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
14 ConSplitterGraphics.c
\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
25 #include "ConSplitter.h"
\r
28 static CHAR16 mCrLfString[3] = { CHAR_CARRIAGE_RETURN, CHAR_LINEFEED, CHAR_NULL };
\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
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
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
52 EFI_SUCCESS - Mode information returned.
\r
53 EFI_INVALID_PARAMETER - Invalid parameters.
\r
57 TEXT_OUT_SPLITTER_PRIVATE_DATA *Private;
\r
60 Private = CONSOLE_CONTROL_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
\r
63 return EFI_INVALID_PARAMETER;
\r
66 *Mode = Private->ConsoleOutputMode;
\r
68 if (GopExists != NULL) {
\r
70 for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {
\r
71 if ((Private->TextOutList[Index].GraphicsOutput != NULL) || (Private->TextOutList[Index].UgaDraw != NULL)) {
\r
78 if (StdInLocked != NULL) {
\r
79 *StdInLocked = ConSpliterConssoleControlStdInLocked ();
\r
87 ConSpliterConsoleControlSetMode (
\r
88 IN EFI_CONSOLE_CONTROL_PROTOCOL *This,
\r
89 IN EFI_CONSOLE_CONTROL_SCREEN_MODE Mode
\r
93 Routine Description:
\r
94 Set the current mode to either text or graphics. Graphics is
\r
98 This - Protocol instance pointer.
\r
99 Mode - Mode to set the
\r
102 EFI_SUCCESS - Mode information returned.
\r
103 EFI_INVALID_PARAMETER - Invalid parameter.
\r
104 EFI_UNSUPPORTED - Operation unsupported.
\r
108 TEXT_OUT_SPLITTER_PRIVATE_DATA *Private;
\r
110 TEXT_OUT_AND_GOP_DATA *TextAndGop;
\r
113 Private = CONSOLE_CONTROL_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
\r
115 if (Mode >= EfiConsoleControlScreenMaxValue) {
\r
116 return EFI_INVALID_PARAMETER;
\r
120 // Judge current mode with wanted mode at first.
\r
122 if (Private->ConsoleOutputMode == Mode) {
\r
123 return EFI_SUCCESS;
\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
135 if ((!Supported) && (Mode == EfiConsoleControlScreenGraphics)) {
\r
136 return EFI_UNSUPPORTED;
\r
139 Private->ConsoleOutputMode = Mode;
\r
141 TextAndGop = &Private->TextOutList[0];
\r
142 for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++, TextAndGop++) {
\r
144 TextAndGop->TextOutEnabled = TRUE;
\r
146 // If we are going into Graphics mode disable ConOut to any UGA device
\r
148 if ((Mode == EfiConsoleControlScreenGraphics) &&((TextAndGop->GraphicsOutput != NULL) || (TextAndGop->UgaDraw != NULL))) {
\r
149 TextAndGop->TextOutEnabled = FALSE;
\r
150 DevNullGopSync (Private, TextAndGop->GraphicsOutput, TextAndGop->UgaDraw);
\r
154 if (Mode == EfiConsoleControlScreenText) {
\r
155 DevNullSyncGopStdOut (Private);
\r
158 return EFI_SUCCESS;
\r
163 ConSpliterGraphicsOutputQueryMode (
\r
164 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
\r
165 IN UINT32 ModeNumber,
\r
166 OUT UINTN *SizeOfInfo,
\r
167 OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
\r
171 Routine Description:
\r
172 Return the current video mode information.
\r
175 This - Protocol instance pointer.
\r
176 ModeNumber - The mode number to return information on.
\r
177 Info - Caller allocated buffer that returns information about ModeNumber.
\r
178 SizeOfInfo - A pointer to the size, in bytes, of the Info buffer.
\r
181 EFI_SUCCESS - Mode information returned.
\r
182 EFI_BUFFER_TOO_SMALL - The Info buffer was too small.
\r
183 EFI_DEVICE_ERROR - A hardware error occurred trying to retrieve the video mode.
\r
184 EFI_NOT_STARTED - Video display is not initialized. Call SetMode ()
\r
185 EFI_INVALID_PARAMETER - One of the input args was NULL.
\r
189 TEXT_OUT_SPLITTER_PRIVATE_DATA *Private;
\r
190 TEXT_OUT_GOP_MODE *Mode;
\r
192 if (This == NULL || Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) {
\r
193 return EFI_INVALID_PARAMETER;
\r
197 // retrieve private data
\r
199 Private = GRAPHICS_OUTPUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
\r
201 if (Private->HardwareNeedsStarting) {
\r
202 return EFI_NOT_STARTED;
\r
205 *Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
\r
207 if (*Info == NULL) {
\r
208 return EFI_OUT_OF_RESOURCES;
\r
211 *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
\r
213 CopyMem (*Info, Private->GraphicsOutput.Mode->Info, *SizeOfInfo);
\r
214 Mode = &Private->GraphicsOutputModeBuffer[ModeNumber];
\r
215 (*Info)->HorizontalResolution = Mode->HorizontalResolution;
\r
216 (*Info)->VerticalResolution = Mode->VerticalResolution;
\r
217 (*Info)->PixelsPerScanLine = Mode->HorizontalResolution;
\r
219 return EFI_SUCCESS;
\r
224 ConSpliterGraphicsOutputSetMode (
\r
225 IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,
\r
226 IN UINT32 ModeNumber
\r
230 Routine Description:
\r
232 Graphics output protocol interface to set video mode
\r
235 This - Protocol instance pointer.
\r
236 ModeNumber - The mode number to be set.
\r
239 EFI_SUCCESS - Graphics mode was changed.
\r
240 EFI_DEVICE_ERROR - The device had an error and could not complete the request.
\r
241 EFI_UNSUPPORTED - ModeNumber is not supported by this device.
\r
246 TEXT_OUT_SPLITTER_PRIVATE_DATA *Private;
\r
248 EFI_STATUS ReturnStatus;
\r
249 TEXT_OUT_GOP_MODE *Mode;
\r
251 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
\r
254 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
\r
255 EFI_UGA_DRAW_PROTOCOL *UgaDraw;
\r
257 if (ModeNumber >= This->Mode->MaxMode) {
\r
258 return EFI_UNSUPPORTED;
\r
261 if (ModeNumber == This->Mode->Mode) {
\r
262 return EFI_SUCCESS;
\r
265 Private = GRAPHICS_OUTPUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
\r
268 // GopDevNullSetMode ()
\r
270 ReturnStatus = EFI_SUCCESS;
\r
273 // Free the old version
\r
275 if (Private->GraphicsOutputBlt != NULL) {
\r
276 FreePool (Private->GraphicsOutputBlt);
\r
280 // Allocate the virtual Blt buffer
\r
282 Mode = &Private->GraphicsOutputModeBuffer[ModeNumber];
\r
283 Size = Mode->HorizontalResolution * Mode->VerticalResolution * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
\r
284 Private->GraphicsOutputBlt = AllocateZeroPool (Size);
\r
286 if (Private->GraphicsOutputBlt == NULL) {
\r
287 return EFI_OUT_OF_RESOURCES;
\r
290 if (!Private->HardwareNeedsStarting) {
\r
291 if (Private->ConsoleOutputMode != EfiConsoleControlScreenGraphics) {
\r
292 return EFI_UNSUPPORTED;
\r
296 // return the worst status met
\r
298 for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {
\r
299 GraphicsOutput = Private->TextOutList[Index].GraphicsOutput;
\r
300 if (GraphicsOutput != NULL) {
\r
302 // Find corresponding ModeNumber of this GraphicsOutput instance
\r
304 for (NumberIndex = 0; NumberIndex < GraphicsOutput->Mode->MaxMode; NumberIndex ++) {
\r
305 Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) NumberIndex, &SizeOfInfo, &Info);
\r
306 if (EFI_ERROR (Status)) {
\r
309 if ((Info->HorizontalResolution == Mode->HorizontalResolution) && (Info->VerticalResolution == Mode->VerticalResolution)) {
\r
316 Status = GraphicsOutput->SetMode (GraphicsOutput, (UINT32) NumberIndex);
\r
317 if (EFI_ERROR (Status)) {
\r
318 ReturnStatus = Status;
\r
322 UgaDraw = Private->TextOutList[Index].UgaDraw;
\r
323 if (UgaDraw != NULL) {
\r
324 Status = UgaDraw->SetMode (
\r
326 Mode->HorizontalResolution,
\r
327 Mode->VerticalResolution,
\r
331 if (EFI_ERROR (Status)) {
\r
332 ReturnStatus = Status;
\r
337 This->Mode->Mode = ModeNumber;
\r
339 Info = This->Mode->Info;
\r
340 Info->HorizontalResolution = Mode->HorizontalResolution;
\r
341 Info->VerticalResolution = Mode->VerticalResolution;
\r
342 Info->PixelsPerScanLine = Mode->HorizontalResolution;
\r
345 // Information is not enough here, so the following items remain unchanged:
\r
346 // GraphicsOutputMode->Info->Version, GraphicsOutputMode->Info->PixelFormat
\r
347 // GraphicsOutputMode->SizeOfInfo, GraphicsOutputMode->FrameBufferBase, GraphicsOutputMode->FrameBufferSize
\r
348 // These items will be initialized/updated when a new GOP device is added into ConsoleSplitter.
\r
351 Private->HardwareNeedsStarting = FALSE;
\r
353 return ReturnStatus;
\r
358 DevNullGraphicsOutputBlt (
\r
359 IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private,
\r
360 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
\r
361 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
\r
364 IN UINTN DestinationX,
\r
365 IN UINTN DestinationY,
\r
368 IN UINTN Delta OPTIONAL
\r
374 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltPtr;
\r
375 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *ScreenPtr;
\r
376 UINTN HorizontalResolution;
\r
377 UINTN VerticalResolution;
\r
379 if ((BltOperation < EfiBltVideoFill) || (BltOperation >= EfiGraphicsOutputBltOperationMax)) {
\r
380 return EFI_INVALID_PARAMETER;
\r
383 if (Width == 0 || Height == 0) {
\r
384 return EFI_INVALID_PARAMETER;
\r
388 Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
\r
391 HorizontalResolution = Private->GraphicsOutput.Mode->Info->HorizontalResolution;
\r
392 VerticalResolution = Private->GraphicsOutput.Mode->Info->VerticalResolution;
\r
395 // We need to fill the Virtual Screen buffer with the blt data.
\r
397 if (BltOperation == EfiBltVideoToBltBuffer) {
\r
399 // Video to BltBuffer: Source is Video, destination is BltBuffer
\r
401 if ((SourceY + Height) > VerticalResolution) {
\r
402 return EFI_INVALID_PARAMETER;
\r
405 if ((SourceX + Width) > HorizontalResolution) {
\r
406 return EFI_INVALID_PARAMETER;
\r
409 BltPtr = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + DestinationY * Delta + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
\r
410 ScreenPtr = &Private->GraphicsOutputBlt[SourceY * HorizontalResolution + SourceX];
\r
412 CopyMem (BltPtr, ScreenPtr, Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
\r
413 BltPtr = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltPtr + Delta);
\r
414 ScreenPtr += HorizontalResolution;
\r
419 // BltBuffer to Video: Source is BltBuffer, destination is Video
\r
421 if (DestinationY + Height > VerticalResolution) {
\r
422 return EFI_INVALID_PARAMETER;
\r
425 if (DestinationX + Width > HorizontalResolution) {
\r
426 return EFI_INVALID_PARAMETER;
\r
429 if ((BltOperation == EfiBltVideoToVideo) && (DestinationY > SourceY)) {
\r
431 // Copy backwards, only care the Video to Video Blt
\r
433 ScreenPtr = &Private->GraphicsOutputBlt[(DestinationY + Height - 1) * HorizontalResolution + DestinationX];
\r
434 SrcY = SourceY + Height - 1;
\r
438 // Copy forwards, for other cases
\r
440 ScreenPtr = &Private->GraphicsOutputBlt[DestinationY * HorizontalResolution + DestinationX];
\r
445 while (Height != 0) {
\r
446 if (BltOperation == EfiBltVideoFill) {
\r
447 for (Index = 0; Index < Width; Index++) {
\r
448 ScreenPtr[Index] = *BltBuffer;
\r
451 if (BltOperation == EfiBltBufferToVideo) {
\r
452 BltPtr = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + SrcY * Delta + SourceX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
\r
454 BltPtr = &Private->GraphicsOutputBlt[SrcY * HorizontalResolution + SourceX];
\r
457 CopyMem (ScreenPtr, BltPtr, Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
\r
461 ScreenPtr += HorizontalResolution;
\r
464 ScreenPtr -= HorizontalResolution;
\r
471 return EFI_SUCCESS;
\r
476 ConSpliterGraphicsOutputBlt (
\r
477 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
\r
478 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
\r
479 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
\r
482 IN UINTN DestinationX,
\r
483 IN UINTN DestinationY,
\r
486 IN UINTN Delta OPTIONAL
\r
490 Routine Description:
\r
491 The following table defines actions for BltOperations:
\r
492 EfiBltVideoFill - Write data from the BltBuffer pixel (SourceX, SourceY)
\r
493 directly to every pixel of the video display rectangle
\r
494 (DestinationX, DestinationY)
\r
495 (DestinationX + Width, DestinationY + Height).
\r
496 Only one pixel will be used from the BltBuffer. Delta is NOT used.
\r
497 EfiBltVideoToBltBuffer - Read data from the video display rectangle
\r
498 (SourceX, SourceY) (SourceX + Width, SourceY + Height) and place it in
\r
499 the BltBuffer rectangle (DestinationX, DestinationY )
\r
500 (DestinationX + Width, DestinationY + Height). If DestinationX or
\r
501 DestinationY is not zero then Delta must be set to the length in bytes
\r
502 of a row in the BltBuffer.
\r
503 EfiBltBufferToVideo - Write data from the BltBuffer rectangle
\r
504 (SourceX, SourceY) (SourceX + Width, SourceY + Height) directly to the
\r
505 video display rectangle (DestinationX, DestinationY)
\r
506 (DestinationX + Width, DestinationY + Height). If SourceX or SourceY is
\r
507 not zero then Delta must be set to the length in bytes of a row in the
\r
509 EfiBltVideoToVideo - Copy from the video display rectangle
\r
510 (SourceX, SourceY) (SourceX + Width, SourceY + Height) .
\r
511 to the video display rectangle (DestinationX, DestinationY)
\r
512 (DestinationX + Width, DestinationY + Height).
\r
513 The BltBuffer and Delta are not used in this mode.
\r
516 This - Protocol instance pointer.
\r
517 BltBuffer - Buffer containing data to blit into video buffer. This
\r
518 buffer has a size of Width*Height*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
\r
519 BltOperation - Operation to perform on BlitBuffer and video memory
\r
520 SourceX - X coordinate of source for the BltBuffer.
\r
521 SourceY - Y coordinate of source for the BltBuffer.
\r
522 DestinationX - X coordinate of destination for the BltBuffer.
\r
523 DestinationY - Y coordinate of destination for the BltBuffer.
\r
524 Width - Width of rectangle in BltBuffer in pixels.
\r
525 Height - Hight of rectangle in BltBuffer in pixels.
\r
529 EFI_SUCCESS - The Blt operation completed.
\r
530 EFI_INVALID_PARAMETER - BltOperation is not valid.
\r
531 EFI_DEVICE_ERROR - A hardware error occured writting to the video
\r
537 TEXT_OUT_SPLITTER_PRIVATE_DATA *Private;
\r
539 EFI_STATUS ReturnStatus;
\r
540 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
\r
541 EFI_UGA_DRAW_PROTOCOL *UgaDraw;
\r
543 Private = GRAPHICS_OUTPUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
\r
546 // Sync up DevNull GOP device
\r
548 ReturnStatus = DevNullGraphicsOutputBlt (
\r
561 if (Private->ConsoleOutputMode != EfiConsoleControlScreenGraphics) {
\r
562 return ReturnStatus;
\r
565 // return the worst status met
\r
567 for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {
\r
568 GraphicsOutput = Private->TextOutList[Index].GraphicsOutput;
\r
569 if (GraphicsOutput != NULL) {
\r
570 Status = GraphicsOutput->Blt (
\r
582 if (EFI_ERROR (Status)) {
\r
583 ReturnStatus = Status;
\r
584 } else if (BltOperation == EfiBltVideoToBltBuffer) {
\r
586 // Only need to read the data into buffer one time
\r
588 return EFI_SUCCESS;
\r
592 UgaDraw = Private->TextOutList[Index].UgaDraw;
\r
593 if (UgaDraw != NULL) {
\r
594 Status = UgaDraw->Blt (
\r
596 (EFI_UGA_PIXEL *) BltBuffer,
\r
597 (EFI_UGA_BLT_OPERATION) BltOperation,
\r
606 if (EFI_ERROR (Status)) {
\r
607 ReturnStatus = Status;
\r
608 } else if (BltOperation == EfiBltVideoToBltBuffer) {
\r
610 // Only need to read the data into buffer one time
\r
612 return EFI_SUCCESS;
\r
617 return ReturnStatus;
\r
622 IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private,
\r
623 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
\r
624 IN EFI_UGA_DRAW_PROTOCOL *UgaDraw
\r
627 if (GraphicsOutput != NULL) {
\r
628 return GraphicsOutput->Blt (
\r
630 Private->GraphicsOutputBlt,
\r
631 EfiBltBufferToVideo,
\r
636 Private->GraphicsOutput.Mode->Info->HorizontalResolution,
\r
637 Private->GraphicsOutput.Mode->Info->VerticalResolution,
\r
641 return UgaDraw->Blt (
\r
643 (EFI_UGA_PIXEL *) Private->GraphicsOutputBlt,
\r
644 EfiUgaBltBufferToVideo,
\r
649 Private->GraphicsOutput.Mode->Info->HorizontalResolution,
\r
650 Private->GraphicsOutput.Mode->Info->VerticalResolution,
\r
658 DevNullTextOutOutputString (
\r
659 IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private,
\r
664 Routine Description:
\r
665 Write a Unicode string to the output device.
\r
668 Private - Pointer to the console output splitter's private data. It
\r
669 indicates the calling context.
\r
670 WString - The NULL-terminated Unicode string to be displayed on the output
\r
671 device(s). All output devices must also support the Unicode
\r
672 drawing defined in this file.
\r
675 EFI_SUCCESS - The string was output to the device.
\r
676 EFI_DEVICE_ERROR - The device reported an error while attempting to
\r
678 EFI_UNSUPPORTED - The output device's mode is not currently in a
\r
680 EFI_WARN_UNKNOWN_GLYPH - This warning code indicates that some of the
\r
681 characters in the Unicode string could not be
\r
682 rendered and were skipped.
\r
687 UINTN SizeAttribute;
\r
689 EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
\r
691 CHAR16 *NullScreen;
\r
696 INT32 *NullAttributes;
\r
697 INT32 CurrentWidth;
\r
701 Mode = &Private->TextOutMode;
\r
702 NullScreen = Private->DevNullScreen;
\r
703 NullAttributes = Private->DevNullAttributes;
\r
704 LastRow = Private->DevNullRows - 1;
\r
705 MaxColumn = Private->DevNullColumns;
\r
707 if (Mode->Attribute & EFI_WIDE_ATTRIBUTE) {
\r
715 if (*WString == CHAR_BACKSPACE) {
\r
717 // If the cursor is at the left edge of the display, then move the cursor
\r
720 if (Mode->CursorColumn == 0 && Mode->CursorRow > 0) {
\r
722 Mode->CursorColumn = (INT32) MaxColumn;
\r
726 // If the cursor is not at the left edge of the display,
\r
727 // then move the cursor left one column.
\r
729 if (Mode->CursorColumn > 0) {
\r
730 Mode->CursorColumn--;
\r
731 if (Mode->CursorColumn > 0 &&
\r
732 NullAttributes[Mode->CursorRow * MaxColumn + Mode->CursorColumn - 1] & EFI_WIDE_ATTRIBUTE
\r
734 Mode->CursorColumn--;
\r
737 // Insert an extra backspace
\r
739 InsertChar = CHAR_BACKSPACE;
\r
740 PStr = WString + 1;
\r
743 *PStr = InsertChar;
\r
744 InsertChar = TempChar;
\r
748 *PStr = InsertChar;
\r
757 } else if (*WString == CHAR_LINEFEED) {
\r
759 // If the cursor is at the bottom of the display,
\r
760 // then scroll the display one row, and do not update
\r
761 // the cursor position. Otherwise, move the cursor down one row.
\r
763 if (Mode->CursorRow == (INT32) (LastRow)) {
\r
765 // Scroll Screen Up One Row
\r
767 SizeAttribute = LastRow * MaxColumn;
\r
770 NullAttributes + MaxColumn,
\r
771 SizeAttribute * sizeof (INT32)
\r
775 // Each row has an ending CHAR_NULL. So one more character each line
\r
776 // for DevNullScreen than DevNullAttributes
\r
778 SizeScreen = SizeAttribute + LastRow;
\r
781 NullScreen + (MaxColumn + 1),
\r
782 SizeScreen * sizeof (CHAR16)
\r
786 // Print Blank Line at last line
\r
788 Screen = NullScreen + SizeScreen;
\r
789 Attribute = NullAttributes + SizeAttribute;
\r
791 for (Index = 0; Index < MaxColumn; Index++, Screen++, Attribute++) {
\r
793 *Attribute = Mode->Attribute;
\r
800 } else if (*WString == CHAR_CARRIAGE_RETURN) {
\r
802 // Move the cursor to the beginning of the current row.
\r
804 Mode->CursorColumn = 0;
\r
808 // Print the character at the current cursor position and
\r
809 // move the cursor right one column. If this moves the cursor
\r
810 // past the right edge of the display, then the line should wrap to
\r
811 // the beginning of the next line. This is equivalent to inserting
\r
812 // a CR and an LF. Note that if the cursor is at the bottom of the
\r
813 // display, and the line wraps, then the display will be scrolled
\r
816 Index = Mode->CursorRow * MaxColumn + Mode->CursorColumn;
\r
818 while (Mode->CursorColumn < (INT32) MaxColumn) {
\r
819 if (*WString == CHAR_NULL) {
\r
823 if (*WString == CHAR_BACKSPACE) {
\r
827 if (*WString == CHAR_LINEFEED) {
\r
831 if (*WString == CHAR_CARRIAGE_RETURN) {
\r
835 if (*WString == UNICODE_WIDE_CHAR || *WString == UNICODE_NARROW_CHAR) {
\r
836 CurrentWidth = (*WString == UNICODE_WIDE_CHAR) ? 2 : 1;
\r
841 if (Mode->CursorColumn + CurrentWidth > (INT32) MaxColumn) {
\r
843 // If a wide char is at the rightmost column, then move the char
\r
844 // to the beginning of the next row
\r
846 NullScreen[Index + Mode->CursorRow] = L' ';
\r
847 NullAttributes[Index] = Mode->Attribute | (UINT32) EFI_WIDE_ATTRIBUTE;
\r
849 Mode->CursorColumn++;
\r
851 NullScreen[Index + Mode->CursorRow] = *WString;
\r
852 NullAttributes[Index] = Mode->Attribute;
\r
853 if (CurrentWidth == 1) {
\r
854 NullAttributes[Index] &= (~ (UINT32) EFI_WIDE_ATTRIBUTE);
\r
856 NullAttributes[Index] |= (UINT32) EFI_WIDE_ATTRIBUTE;
\r
857 NullAttributes[Index + 1] &= (~ (UINT32) EFI_WIDE_ATTRIBUTE);
\r
860 Index += CurrentWidth;
\r
862 Mode->CursorColumn += CurrentWidth;
\r
866 // At the end of line, output carriage return and line feed
\r
868 if (Mode->CursorColumn >= (INT32) MaxColumn) {
\r
869 DevNullTextOutOutputString (Private, mCrLfString);
\r
874 return EFI_SUCCESS;
\r
878 DevNullTextOutSetMode (
\r
879 IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private,
\r
880 IN UINTN ModeNumber
\r
884 Routine Description:
\r
885 Sets the output device(s) to a specified mode.
\r
888 Private - Private data structure pointer.
\r
889 ModeNumber - The mode number to set.
\r
892 EFI_SUCCESS - The requested text mode was set.
\r
893 EFI_DEVICE_ERROR - The device had an error and
\r
894 could not complete the request.
\r
895 EFI_UNSUPPORTED - The mode number was not valid.
\r
896 EFI_OUT_OF_RESOURCES - Out of resources.
\r
903 TEXT_OUT_SPLITTER_QUERY_DATA *Mode;
\r
906 // No extra check for ModeNumber here, as it has been checked in
\r
907 // ConSplitterTextOutSetMode. And mode 0 should always be supported.
\r
909 Mode = &(Private->TextOutQueryData[ModeNumber]);
\r
911 Column = Mode->Columns;
\r
913 if (Row <= 0 && Column <= 0) {
\r
914 return EFI_UNSUPPORTED;
\r
917 if (Private->DevNullColumns != Column || Private->DevNullRows != Row) {
\r
919 Private->TextOutMode.Mode = (INT32) ModeNumber;
\r
920 Private->DevNullColumns = Column;
\r
921 Private->DevNullRows = Row;
\r
923 if (Private->DevNullScreen != NULL) {
\r
924 FreePool (Private->DevNullScreen);
\r
927 Size = (Row * (Column + 1)) * sizeof (CHAR16);
\r
928 Private->DevNullScreen = AllocateZeroPool (Size);
\r
929 if (Private->DevNullScreen == NULL) {
\r
930 return EFI_OUT_OF_RESOURCES;
\r
933 if (Private->DevNullAttributes != NULL) {
\r
934 FreePool (Private->DevNullAttributes);
\r
937 Size = Row * Column * sizeof (INT32);
\r
938 Private->DevNullAttributes = AllocateZeroPool (Size);
\r
939 if (Private->DevNullAttributes == NULL) {
\r
940 return EFI_OUT_OF_RESOURCES;
\r
944 DevNullTextOutClearScreen (Private);
\r
946 return EFI_SUCCESS;
\r
950 DevNullTextOutClearScreen (
\r
951 IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private
\r
955 Routine Description:
\r
956 Clears the output device(s) display to the currently selected background
\r
960 Private - Protocol instance pointer.
\r
963 EFI_SUCCESS - The operation completed successfully.
\r
964 EFI_DEVICE_ERROR - The device had an error and
\r
965 could not complete the request.
\r
966 EFI_UNSUPPORTED - The output device is not in a valid text mode.
\r
974 INT32 CurrentAttribute;
\r
977 // Clear the DevNull Text Out Buffers.
\r
978 // The screen is filled with spaces.
\r
979 // The attributes are all synced with the current Simple Text Out Attribute
\r
981 Screen = Private->DevNullScreen;
\r
982 Attributes = Private->DevNullAttributes;
\r
983 CurrentAttribute = Private->TextOutMode.Attribute;
\r
985 for (Row = 0; Row < Private->DevNullRows; Row++) {
\r
986 for (Column = 0; Column < Private->DevNullColumns; Column++, Screen++, Attributes++) {
\r
988 *Attributes = CurrentAttribute;
\r
991 // Each line of the screen has a NULL on the end so we must skip over it
\r
996 DevNullTextOutSetCursorPosition (Private, 0, 0);
\r
998 return DevNullTextOutEnableCursor (Private, TRUE);
\r
1002 DevNullTextOutSetCursorPosition (
\r
1003 IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private,
\r
1009 Routine Description:
\r
1010 Sets the current coordinates of the cursor position
\r
1013 Private - Protocol instance pointer.
\r
1014 Column, Row - the position to set the cursor to. Must be greater than or
\r
1015 equal to zero and less than the number of columns and rows
\r
1019 EFI_SUCCESS - The operation completed successfully.
\r
1020 EFI_DEVICE_ERROR - The device had an error and
\r
1021 could not complete the request.
\r
1022 EFI_UNSUPPORTED - The output device is not in a valid text mode, or the
\r
1023 cursor position is invalid for the current mode.
\r
1028 // No need to do extra check here as whether (Column, Row) is valid has
\r
1029 // been checked in ConSplitterTextOutSetCursorPosition. And (0, 0) should
\r
1030 // always be supported.
\r
1032 Private->TextOutMode.CursorColumn = (INT32) Column;
\r
1033 Private->TextOutMode.CursorRow = (INT32) Row;
\r
1035 return EFI_SUCCESS;
\r
1039 DevNullTextOutEnableCursor (
\r
1040 IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private,
\r
1041 IN BOOLEAN Visible
\r
1044 Routine Description:
\r
1046 Implements SIMPLE_TEXT_OUTPUT.EnableCursor().
\r
1047 In this driver, the cursor cannot be hidden.
\r
1051 Private - Indicates the calling context.
\r
1053 Visible - If TRUE, the cursor is set to be visible, If FALSE, the cursor
\r
1054 is set to be invisible.
\r
1058 EFI_SUCCESS - The request is valid.
\r
1063 Private->TextOutMode.CursorVisible = Visible;
\r
1065 return EFI_SUCCESS;
\r
1069 DevNullSyncGopStdOut (
\r
1070 IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private
\r
1073 Routine Description:
\r
1074 Take the DevNull TextOut device and update the Simple Text Out on every
\r
1078 Private - Indicates the calling context.
\r
1081 EFI_SUCCESS - The request is valid.
\r
1082 other - Return status of TextOut->OutputString ()
\r
1086 EFI_STATUS Status;
\r
1087 EFI_STATUS ReturnStatus;
\r
1092 UINTN CurrentColumn;
\r
1094 UINTN StartColumn;
\r
1095 INT32 StartAttribute;
\r
1096 BOOLEAN StartCursorState;
\r
1100 CHAR16 *BufferTail;
\r
1101 CHAR16 *ScreenStart;
\r
1102 INT32 CurrentAttribute;
\r
1103 INT32 *Attributes;
\r
1104 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Sto;
\r
1107 // Save the devices Attributes, Cursor enable state and location
\r
1109 StartColumn = Private->TextOutMode.CursorColumn;
\r
1110 StartRow = Private->TextOutMode.CursorRow;
\r
1111 StartAttribute = Private->TextOutMode.Attribute;
\r
1112 StartCursorState = Private->TextOutMode.CursorVisible;
\r
1114 for (List = 0; List < Private->CurrentNumberOfConsoles; List++) {
\r
1116 Sto = Private->TextOutList[List].TextOut;
\r
1119 // Skip non GOP/UGA devices
\r
1121 if ((Private->TextOutList[List].GraphicsOutput != NULL) || (Private->TextOutList[List].UgaDraw != NULL)) {
\r
1122 Sto->EnableCursor (Sto, FALSE);
\r
1123 Sto->ClearScreen (Sto);
\r
1127 ReturnStatus = EFI_SUCCESS;
\r
1128 Screen = Private->DevNullScreen;
\r
1129 Attributes = Private->DevNullAttributes;
\r
1130 MaxColumn = Private->DevNullColumns;
\r
1132 Buffer = AllocateZeroPool ((MaxColumn + 1) * sizeof (CHAR16));
\r
1133 if (Buffer == NULL) {
\r
1134 return ReturnStatus;
\r
1137 for (Row = 0; Row < Private->DevNullRows; Row++, Screen += (MaxColumn + 1), Attributes += MaxColumn) {
\r
1139 if (Row == (Private->DevNullRows - 1)) {
\r
1141 // Don't ever sync the last character as it will scroll the screen
\r
1143 Screen[MaxColumn - 1] = 0x00;
\r
1147 while (Column < MaxColumn) {
\r
1148 if (Screen[Column]) {
\r
1149 CurrentAttribute = Attributes[Column];
\r
1150 CurrentColumn = Column;
\r
1151 ScreenStart = &Screen[Column];
\r
1154 // the line end is alway 0x0. So Column should be less than MaxColumn
\r
1155 // It should be still in the same row
\r
1157 for (Str = ScreenStart, BufferTail = Buffer; *Str != 0; Str++, Column++) {
\r
1159 if (Attributes[Column] != CurrentAttribute) {
\r
1164 *BufferTail = *Str;
\r
1166 if (Attributes[Column] & EFI_WIDE_ATTRIBUTE) {
\r
1174 for (List = 0; List < Private->CurrentNumberOfConsoles; List++) {
\r
1176 Sto = Private->TextOutList[List].TextOut;
\r
1179 // Skip non GOP/UGA devices
\r
1181 if ((Private->TextOutList[List].GraphicsOutput != NULL) || (Private->TextOutList[List].UgaDraw != NULL)) {
\r
1182 Sto->SetAttribute (Sto, CurrentAttribute);
\r
1183 Sto->SetCursorPosition (Sto, CurrentColumn, Row);
\r
1184 Status = Sto->OutputString (Sto, Buffer);
\r
1185 if (EFI_ERROR (Status)) {
\r
1186 ReturnStatus = Status;
\r
1197 // Restore the devices Attributes, Cursor enable state and location
\r
1199 for (List = 0; List < Private->CurrentNumberOfConsoles; List++) {
\r
1200 Sto = Private->TextOutList[List].TextOut;
\r
1203 // Skip non GOP/UGA devices
\r
1205 if ((Private->TextOutList[List].GraphicsOutput != NULL) || (Private->TextOutList[List].UgaDraw != NULL)) {
\r
1206 Sto->SetAttribute (Sto, StartAttribute);
\r
1207 Sto->SetCursorPosition (Sto, StartColumn, StartRow);
\r
1208 Status = Sto->EnableCursor (Sto, StartCursorState);
\r
1209 if (EFI_ERROR (Status)) {
\r
1210 ReturnStatus = Status;
\r
1215 FreePool (Buffer);
\r
1217 return ReturnStatus;
\r