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