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