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