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