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