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