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