]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Universal/Console/ConSplitter/Dxe/ConSplitterGraphics.c
Updated MSA by putting Specification element at the end of the header section
[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 *UgaExists,
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->UgaMode;
67
68 if (UgaExists != NULL) {
69 *UgaExists = FALSE;
70 for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {
71 if (Private->TextOutList[Index].UgaDraw != NULL) {
72 *UgaExists = 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_UGA_DATA *TextAndUga;
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 TextAndUga = &Private->TextOutList[0];
121 for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++, TextAndUga++) {
122 if (TextAndUga->UgaDraw != NULL) {
123 Supported = TRUE;
124 break;
125 }
126 }
127
128 if ((!Supported) && (Mode == EfiConsoleControlScreenGraphics)) {
129 return EFI_UNSUPPORTED;
130 }
131
132 Private->UgaMode = Mode;
133
134 TextAndUga = &Private->TextOutList[0];
135 for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++, TextAndUga++) {
136
137 TextAndUga->TextOutEnabled = TRUE;
138 //
139 // If we are going into Graphics mode disable ConOut to any UGA device
140 //
141 if ((Mode == EfiConsoleControlScreenGraphics) && (TextAndUga->UgaDraw != NULL)) {
142 TextAndUga->TextOutEnabled = FALSE;
143 DevNullUgaSync (Private, TextAndUga->UgaDraw);
144 }
145 }
146
147 if (Mode == EfiConsoleControlScreenText) {
148 DevNullSyncUgaStdOut (Private);
149 }
150
151 return EFI_SUCCESS;
152 }
153
154 EFI_STATUS
155 EFIAPI
156 ConSpliterUgaDrawGetMode (
157 IN EFI_UGA_DRAW_PROTOCOL *This,
158 OUT UINT32 *HorizontalResolution,
159 OUT UINT32 *VerticalResolution,
160 OUT UINT32 *ColorDepth,
161 OUT UINT32 *RefreshRate
162 )
163 /*++
164
165 Routine Description:
166 Return the current video mode information.
167
168 Arguments:
169 This - Protocol instance pointer.
170 HorizontalResolution - Current video horizontal resolution in pixels
171 VerticalResolution - Current video vertical resolution in pixels
172 ColorDepth - Current video color depth in bits per pixel
173 RefreshRate - Current video refresh rate in Hz.
174
175 Returns:
176 EFI_SUCCESS - Mode information returned.
177 EFI_NOT_STARTED - Video display is not initialized. Call SetMode ()
178 EFI_INVALID_PARAMETER - One of the input args was NULL.
179
180 --*/
181 {
182 TEXT_OUT_SPLITTER_PRIVATE_DATA *Private;
183
184 if (!(HorizontalResolution && VerticalResolution && RefreshRate && ColorDepth)) {
185 return EFI_INVALID_PARAMETER;
186 }
187 //
188 // retrieve private data
189 //
190 Private = UGA_DRAW_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
191
192 *HorizontalResolution = Private->UgaHorizontalResolution;
193 *VerticalResolution = Private->UgaVerticalResolution;
194 *ColorDepth = Private->UgaColorDepth;
195 *RefreshRate = Private->UgaRefreshRate;
196
197 return EFI_SUCCESS;
198 }
199
200 EFI_STATUS
201 EFIAPI
202 ConSpliterUgaDrawSetMode (
203 IN EFI_UGA_DRAW_PROTOCOL *This,
204 IN UINT32 HorizontalResolution,
205 IN UINT32 VerticalResolution,
206 IN UINT32 ColorDepth,
207 IN UINT32 RefreshRate
208 )
209 /*++
210
211 Routine Description:
212 Return the current video mode information.
213
214 Arguments:
215 This - Protocol instance pointer.
216 HorizontalResolution - Current video horizontal resolution in pixels
217 VerticalResolution - Current video vertical resolution in pixels
218 ColorDepth - Current video color depth in bits per pixel
219 RefreshRate - Current video refresh rate in Hz.
220
221 Returns:
222 EFI_SUCCESS - Mode information returned.
223 EFI_NOT_STARTED - Video display is not initialized. Call SetMode ()
224 EFI_OUT_OF_RESOURCES - Out of resources.
225
226 --*/
227 {
228 EFI_STATUS Status;
229 TEXT_OUT_SPLITTER_PRIVATE_DATA *Private;
230 UINTN Index;
231 EFI_STATUS ReturnStatus;
232 UINTN Size;
233
234 Private = UGA_DRAW_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
235
236 //
237 // UgaDevNullSetMode ()
238 //
239 ReturnStatus = EFI_SUCCESS;
240
241 //
242 // Free the old version
243 //
244 gBS->FreePool (Private->UgaBlt);
245
246 //
247 // Allocate the virtual Blt buffer
248 //
249 Size = HorizontalResolution * VerticalResolution * sizeof (EFI_UGA_PIXEL);
250 Private->UgaBlt = AllocateZeroPool (Size);
251 if (Private->UgaBlt == NULL) {
252 return EFI_OUT_OF_RESOURCES;
253 }
254
255 //
256 // Update the Mode data
257 //
258 Private->UgaHorizontalResolution = HorizontalResolution;
259 Private->UgaVerticalResolution = VerticalResolution;
260 Private->UgaColorDepth = ColorDepth;
261 Private->UgaRefreshRate = RefreshRate;
262
263 if (Private->UgaMode != EfiConsoleControlScreenGraphics) {
264 return ReturnStatus;
265 }
266 //
267 // return the worst status met
268 //
269 for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {
270 if (Private->TextOutList[Index].UgaDraw != NULL) {
271 Status = Private->TextOutList[Index].UgaDraw->SetMode (
272 Private->TextOutList[Index].UgaDraw,
273 HorizontalResolution,
274 VerticalResolution,
275 ColorDepth,
276 RefreshRate
277 );
278 if (EFI_ERROR (Status)) {
279 ReturnStatus = Status;
280 }
281 }
282 }
283
284 return ReturnStatus;
285 }
286
287 EFI_STATUS
288 DevNullUgaBlt (
289 IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private,
290 IN EFI_UGA_PIXEL *BltBuffer, OPTIONAL
291 IN EFI_UGA_BLT_OPERATION BltOperation,
292 IN UINTN SourceX,
293 IN UINTN SourceY,
294 IN UINTN DestinationX,
295 IN UINTN DestinationY,
296 IN UINTN Width,
297 IN UINTN Height,
298 IN UINTN Delta OPTIONAL
299 )
300 {
301 UINTN SrcY;
302 UINTN Index;
303 EFI_UGA_PIXEL *BltPtr;
304 EFI_UGA_PIXEL *ScreenPtr;
305 UINT32 HorizontalResolution;
306 UINT32 VerticalResolution;
307
308 if ((BltOperation < 0) || (BltOperation >= EfiUgaBltMax)) {
309 return EFI_INVALID_PARAMETER;
310 }
311
312 if (Width == 0 || Height == 0) {
313 return EFI_INVALID_PARAMETER;
314 }
315
316 if (Delta == 0) {
317 Delta = Width * sizeof (EFI_UGA_PIXEL);
318 }
319
320 HorizontalResolution = Private->UgaHorizontalResolution;
321 VerticalResolution = Private->UgaVerticalResolution;
322
323 //
324 // We need to fill the Virtual Screen buffer with the blt data.
325 //
326 if (BltOperation == EfiUgaVideoToBltBuffer) {
327 //
328 // Video to BltBuffer: Source is Video, destination is BltBuffer
329 //
330 if ((SourceY + Height) > VerticalResolution) {
331 return EFI_INVALID_PARAMETER;
332 }
333
334 if ((SourceX + Width) > HorizontalResolution) {
335 return EFI_INVALID_PARAMETER;
336 }
337
338 BltPtr = (EFI_UGA_PIXEL *) ((UINT8 *) BltBuffer + DestinationY * Delta + DestinationX * sizeof (EFI_UGA_PIXEL));
339 ScreenPtr = &Private->UgaBlt[SourceY * HorizontalResolution + SourceX];
340 while (Height) {
341 CopyMem (BltPtr, ScreenPtr, Width * sizeof (EFI_UGA_PIXEL));
342 BltPtr = (EFI_UGA_PIXEL *) ((UINT8 *) BltPtr + Delta);
343 ScreenPtr += HorizontalResolution;
344 Height--;
345 }
346 } else {
347 //
348 // BltBuffer to Video: Source is BltBuffer, destination is Video
349 //
350 if (DestinationY + Height > VerticalResolution) {
351 return EFI_INVALID_PARAMETER;
352 }
353
354 if (DestinationX + Width > HorizontalResolution) {
355 return EFI_INVALID_PARAMETER;
356 }
357
358 ScreenPtr = &Private->UgaBlt[DestinationY * HorizontalResolution + DestinationX];
359 SrcY = SourceY;
360 while (Height) {
361 if (BltOperation == EfiUgaVideoFill) {
362 for (Index = 0; Index < Width; Index++) {
363 ScreenPtr[Index] = *BltBuffer;
364 }
365 } else {
366 if (BltOperation == EfiUgaBltBufferToVideo) {
367 BltPtr = (EFI_UGA_PIXEL *) ((UINT8 *) BltBuffer + SrcY * Delta + SourceX * sizeof (EFI_UGA_PIXEL));
368 } else {
369 BltPtr = &Private->UgaBlt[SrcY * HorizontalResolution + SourceX];
370 }
371
372 CopyMem (ScreenPtr, BltPtr, Width * sizeof (EFI_UGA_PIXEL));
373 }
374
375 ScreenPtr += HorizontalResolution;
376 SrcY++;
377 Height--;
378 }
379 }
380
381 return EFI_SUCCESS;
382 }
383
384 EFI_STATUS
385 EFIAPI
386 ConSpliterUgaDrawBlt (
387 IN EFI_UGA_DRAW_PROTOCOL *This,
388 IN EFI_UGA_PIXEL *BltBuffer, OPTIONAL
389 IN EFI_UGA_BLT_OPERATION BltOperation,
390 IN UINTN SourceX,
391 IN UINTN SourceY,
392 IN UINTN DestinationX,
393 IN UINTN DestinationY,
394 IN UINTN Width,
395 IN UINTN Height,
396 IN UINTN Delta OPTIONAL
397 )
398 /*++
399
400 Routine Description:
401 The following table defines actions for BltOperations:
402 EfiUgaVideoFill - Write data from the BltBuffer pixel (SourceX, SourceY)
403 directly to every pixel of the video display rectangle
404 (DestinationX, DestinationY)
405 (DestinationX + Width, DestinationY + Height).
406 Only one pixel will be used from the BltBuffer. Delta is NOT used.
407 EfiUgaVideoToBltBuffer - Read data from the video display rectangle
408 (SourceX, SourceY) (SourceX + Width, SourceY + Height) and place it in
409 the BltBuffer rectangle (DestinationX, DestinationY )
410 (DestinationX + Width, DestinationY + Height). If DestinationX or
411 DestinationY is not zero then Delta must be set to the length in bytes
412 of a row in the BltBuffer.
413 EfiUgaBltBufferToVideo - Write data from the BltBuffer rectangle
414 (SourceX, SourceY) (SourceX + Width, SourceY + Height) directly to the
415 video display rectangle (DestinationX, DestinationY)
416 (DestinationX + Width, DestinationY + Height). If SourceX or SourceY is
417 not zero then Delta must be set to the length in bytes of a row in the
418 BltBuffer.
419 EfiUgaVideoToVideo - Copy from the video display rectangle
420 (SourceX, SourceY) (SourceX + Width, SourceY + Height) .
421 to the video display rectangle (DestinationX, DestinationY)
422 (DestinationX + Width, DestinationY + Height).
423 The BltBuffer and Delta are not used in this mode.
424
425 Arguments:
426 This - Protocol instance pointer.
427 BltBuffer - Buffer containing data to blit into video buffer. This
428 buffer has a size of Width*Height*sizeof(EFI_UGA_PIXEL)
429 BltOperation - Operation to perform on BlitBuffer and video memory
430 SourceX - X coordinate of source for the BltBuffer.
431 SourceY - Y coordinate of source for the BltBuffer.
432 DestinationX - X coordinate of destination for the BltBuffer.
433 DestinationY - Y coordinate of destination for the BltBuffer.
434 Width - Width of rectangle in BltBuffer in pixels.
435 Height - Hight of rectangle in BltBuffer in pixels.
436 Delta -
437
438 Returns:
439 EFI_SUCCESS - The Blt operation completed.
440 EFI_INVALID_PARAMETER - BltOperation is not valid.
441 EFI_DEVICE_ERROR - A hardware error occured writting to the video
442 buffer.
443
444 --*/
445 {
446 EFI_STATUS Status;
447 TEXT_OUT_SPLITTER_PRIVATE_DATA *Private;
448 UINTN Index;
449 EFI_STATUS ReturnStatus;
450
451 Private = UGA_DRAW_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
452
453 //
454 // Sync up DevNull UGA device
455 //
456 ReturnStatus = DevNullUgaBlt (
457 Private,
458 BltBuffer,
459 BltOperation,
460 SourceX,
461 SourceY,
462 DestinationX,
463 DestinationY,
464 Width,
465 Height,
466 Delta
467 );
468 if (Private->UgaMode != EfiConsoleControlScreenGraphics) {
469 return ReturnStatus;
470 }
471 //
472 // return the worst status met
473 //
474 for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {
475 if (Private->TextOutList[Index].UgaDraw != NULL) {
476 Status = Private->TextOutList[Index].UgaDraw->Blt (
477 Private->TextOutList[Index].UgaDraw,
478 BltBuffer,
479 BltOperation,
480 SourceX,
481 SourceY,
482 DestinationX,
483 DestinationY,
484 Width,
485 Height,
486 Delta
487 );
488 if (EFI_ERROR (Status)) {
489 ReturnStatus = Status;
490 } else if (BltOperation == EfiUgaVideoToBltBuffer) {
491 //
492 // Only need to read the data into buffer one time
493 //
494 return EFI_SUCCESS;
495 }
496 }
497 }
498
499 return ReturnStatus;
500 }
501
502 EFI_STATUS
503 DevNullUgaSync (
504 IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private,
505 IN EFI_UGA_DRAW_PROTOCOL *UgaDraw
506 )
507 {
508 return UgaDraw->Blt (
509 UgaDraw,
510 Private->UgaBlt,
511 EfiUgaBltBufferToVideo,
512 0,
513 0,
514 0,
515 0,
516 Private->UgaHorizontalResolution,
517 Private->UgaVerticalResolution,
518 Private->UgaHorizontalResolution * sizeof (EFI_UGA_PIXEL)
519 );
520 }
521
522 EFI_STATUS
523 DevNullTextOutOutputString (
524 IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private,
525 IN CHAR16 *WString
526 )
527 /*++
528
529 Routine Description:
530 Write a Unicode string to the output device.
531
532 Arguments:
533 Private - Pointer to the console output splitter's private data. It
534 indicates the calling context.
535 WString - The NULL-terminated Unicode string to be displayed on the output
536 device(s). All output devices must also support the Unicode
537 drawing defined in this file.
538
539 Returns:
540 EFI_SUCCESS - The string was output to the device.
541 EFI_DEVICE_ERROR - The device reported an error while attempting to
542 output the text.
543 EFI_UNSUPPORTED - The output device's mode is not currently in a
544 defined text mode.
545 EFI_WARN_UNKNOWN_GLYPH - This warning code indicates that some of the
546 characters in the Unicode string could not be
547 rendered and were skipped.
548
549 --*/
550 {
551 UINTN SizeScreen;
552 UINTN SizeAttribute;
553 UINTN Index;
554 EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
555 CHAR16 *Screen;
556 CHAR16 *NullScreen;
557 CHAR16 InsertChar;
558 CHAR16 TempChar;
559 CHAR16 *PStr;
560 INT32 *Attribute;
561 INT32 *NullAttributes;
562 INT32 CurrentWidth;
563 UINTN LastRow;
564 UINTN MaxColumn;
565
566 Mode = &Private->TextOutMode;
567 NullScreen = Private->DevNullScreen;
568 NullAttributes = Private->DevNullAttributes;
569 LastRow = Private->DevNullRows - 1;
570 MaxColumn = Private->DevNullColumns;
571
572 if (Mode->Attribute & EFI_WIDE_ATTRIBUTE) {
573 CurrentWidth = 2;
574 } else {
575 CurrentWidth = 1;
576 }
577
578 while (*WString) {
579
580 if (*WString == CHAR_BACKSPACE) {
581 //
582 // If the cursor is at the left edge of the display, then move the cursor
583 // one row up.
584 //
585 if (Mode->CursorColumn == 0 && Mode->CursorRow > 0) {
586 Mode->CursorRow--;
587 Mode->CursorColumn = (INT32) MaxColumn;
588 }
589
590 //
591 // If the cursor is not at the left edge of the display,
592 // then move the cursor left one column.
593 //
594 if (Mode->CursorColumn > 0) {
595 Mode->CursorColumn--;
596 if (Mode->CursorColumn > 0 &&
597 NullAttributes[Mode->CursorRow * MaxColumn + Mode->CursorColumn - 1] & EFI_WIDE_ATTRIBUTE
598 ) {
599 Mode->CursorColumn--;
600
601 //
602 // Insert an extra backspace
603 //
604 InsertChar = CHAR_BACKSPACE;
605 PStr = WString + 1;
606 while (*PStr) {
607 TempChar = *PStr;
608 *PStr = InsertChar;
609 InsertChar = TempChar;
610 PStr++;
611 }
612
613 *PStr = InsertChar;
614 *(++PStr) = 0;
615
616 WString++;
617 }
618 }
619
620 WString++;
621
622 } else if (*WString == CHAR_LINEFEED) {
623 //
624 // If the cursor is at the bottom of the display,
625 // then scroll the display one row, and do not update
626 // the cursor position. Otherwise, move the cursor down one row.
627 //
628 if (Mode->CursorRow == (INT32) (LastRow)) {
629 //
630 // Scroll Screen Up One Row
631 //
632 SizeAttribute = LastRow * MaxColumn;
633 CopyMem (
634 NullAttributes,
635 NullAttributes + MaxColumn,
636 SizeAttribute * sizeof (INT32)
637 );
638
639 //
640 // Each row has an ending CHAR_NULL. So one more character each line
641 // for DevNullScreen than DevNullAttributes
642 //
643 SizeScreen = SizeAttribute + LastRow;
644 CopyMem (
645 NullScreen,
646 NullScreen + (MaxColumn + 1),
647 SizeScreen * sizeof (CHAR16)
648 );
649
650 //
651 // Print Blank Line at last line
652 //
653 Screen = NullScreen + SizeScreen;
654 Attribute = NullAttributes + SizeAttribute;
655
656 for (Index = 0; Index < MaxColumn; Index++, Screen++, Attribute++) {
657 *Screen = ' ';
658 *Attribute = Mode->Attribute;
659 }
660 } else {
661 Mode->CursorRow++;
662 }
663
664 WString++;
665 } else if (*WString == CHAR_CARRIAGE_RETURN) {
666 //
667 // Move the cursor to the beginning of the current row.
668 //
669 Mode->CursorColumn = 0;
670 WString++;
671 } else {
672 //
673 // Print the character at the current cursor position and
674 // move the cursor right one column. If this moves the cursor
675 // past the right edge of the display, then the line should wrap to
676 // the beginning of the next line. This is equivalent to inserting
677 // a CR and an LF. Note that if the cursor is at the bottom of the
678 // display, and the line wraps, then the display will be scrolled
679 // one line.
680 //
681 Index = Mode->CursorRow * MaxColumn + Mode->CursorColumn;
682
683 while (Mode->CursorColumn < (INT32) MaxColumn) {
684 if (*WString == CHAR_NULL) {
685 break;
686 }
687
688 if (*WString == CHAR_BACKSPACE) {
689 break;
690 }
691
692 if (*WString == CHAR_LINEFEED) {
693 break;
694 }
695
696 if (*WString == CHAR_CARRIAGE_RETURN) {
697 break;
698 }
699
700 if (*WString == WIDE_CHAR || *WString == NARROW_CHAR) {
701 CurrentWidth = (*WString == WIDE_CHAR) ? 2 : 1;
702 WString++;
703 continue;
704 }
705
706 if (Mode->CursorColumn + CurrentWidth > (INT32) MaxColumn) {
707 //
708 // If a wide char is at the rightmost column, then move the char
709 // to the beginning of the next row
710 //
711 NullScreen[Index + Mode->CursorRow] = L' ';
712 NullAttributes[Index] = Mode->Attribute | (UINT32) EFI_WIDE_ATTRIBUTE;
713 Index++;
714 Mode->CursorColumn++;
715 } else {
716 NullScreen[Index + Mode->CursorRow] = *WString;
717 NullAttributes[Index] = Mode->Attribute;
718 if (CurrentWidth == 1) {
719 NullAttributes[Index] &= (~ (UINT32) EFI_WIDE_ATTRIBUTE);
720 } else {
721 NullAttributes[Index] |= (UINT32) EFI_WIDE_ATTRIBUTE;
722 NullAttributes[Index + 1] &= (~ (UINT32) EFI_WIDE_ATTRIBUTE);
723 }
724
725 Index += CurrentWidth;
726 WString++;
727 Mode->CursorColumn += CurrentWidth;
728 }
729 }
730 //
731 // At the end of line, output carriage return and line feed
732 //
733 if (Mode->CursorColumn >= (INT32) MaxColumn) {
734 DevNullTextOutOutputString (Private, mCrLfString);
735 }
736 }
737 }
738
739 return EFI_SUCCESS;
740 }
741
742 EFI_STATUS
743 DevNullTextOutSetMode (
744 IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private,
745 IN UINTN ModeNumber
746 )
747 /*++
748
749 Routine Description:
750 Sets the output device(s) to a specified mode.
751
752 Arguments:
753 Private - Private data structure pointer.
754 ModeNumber - The mode number to set.
755
756 Returns:
757 EFI_SUCCESS - The requested text mode was set.
758 EFI_DEVICE_ERROR - The device had an error and
759 could not complete the request.
760 EFI_UNSUPPORTED - The mode number was not valid.
761 EFI_OUT_OF_RESOURCES - Out of resources.
762
763 --*/
764 {
765 UINTN Size;
766 UINTN Row;
767 UINTN Column;
768 TEXT_OUT_SPLITTER_QUERY_DATA *Mode;
769
770 //
771 // No extra check for ModeNumber here, as it has been checked in
772 // ConSplitterTextOutSetMode. And mode 0 should always be supported.
773 //
774 Mode = &(Private->TextOutQueryData[ModeNumber]);
775 Row = Mode->Rows;
776 Column = Mode->Columns;
777
778 if (Row <= 0 && Column <= 0) {
779 return EFI_UNSUPPORTED;
780 }
781
782 if (Private->DevNullColumns != Column || Private->DevNullRows != Row) {
783
784 Private->TextOutMode.Mode = (INT32) ModeNumber;
785 Private->DevNullColumns = Column;
786 Private->DevNullRows = Row;
787
788 gBS->FreePool (Private->DevNullScreen);
789
790 Size = (Row * (Column + 1)) * sizeof (CHAR16);
791 Private->DevNullScreen = AllocateZeroPool (Size);
792 if (Private->DevNullScreen == NULL) {
793 return EFI_OUT_OF_RESOURCES;
794 }
795
796 gBS->FreePool (Private->DevNullAttributes);
797
798 Size = Row * Column * sizeof (INT32);
799 Private->DevNullAttributes = AllocateZeroPool (Size);
800 if (Private->DevNullAttributes == NULL) {
801 return EFI_OUT_OF_RESOURCES;
802 }
803 }
804
805 DevNullTextOutClearScreen (Private);
806
807 return EFI_SUCCESS;
808 }
809
810 EFI_STATUS
811 DevNullTextOutClearScreen (
812 IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private
813 )
814 /*++
815
816 Routine Description:
817 Clears the output device(s) display to the currently selected background
818 color.
819
820 Arguments:
821 Private - Protocol instance pointer.
822
823 Returns:
824 EFI_SUCCESS - The operation completed successfully.
825 EFI_DEVICE_ERROR - The device had an error and
826 could not complete the request.
827 EFI_UNSUPPORTED - The output device is not in a valid text mode.
828
829 --*/
830 {
831 UINTN Row;
832 UINTN Column;
833 CHAR16 *Screen;
834 INT32 *Attributes;
835 INT32 CurrentAttribute;
836
837 //
838 // Clear the DevNull Text Out Buffers.
839 // The screen is filled with spaces.
840 // The attributes are all synced with the current Simple Text Out Attribute
841 //
842 Screen = Private->DevNullScreen;
843 Attributes = Private->DevNullAttributes;
844 CurrentAttribute = Private->TextOutMode.Attribute;
845
846 for (Row = 0; Row < Private->DevNullRows; Row++) {
847 for (Column = 0; Column < Private->DevNullColumns; Column++, Screen++, Attributes++) {
848 *Screen = ' ';
849 *Attributes = CurrentAttribute;
850 }
851 //
852 // Each line of the screen has a NULL on the end so we must skip over it
853 //
854 Screen++;
855 }
856
857 DevNullTextOutSetCursorPosition (Private, 0, 0);
858
859 return DevNullTextOutEnableCursor (Private, TRUE);
860 }
861
862 EFI_STATUS
863 DevNullTextOutSetCursorPosition (
864 IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private,
865 IN UINTN Column,
866 IN UINTN Row
867 )
868 /*++
869
870 Routine Description:
871 Sets the current coordinates of the cursor position
872
873 Arguments:
874 Private - Protocol instance pointer.
875 Column, Row - the position to set the cursor to. Must be greater than or
876 equal to zero and less than the number of columns and rows
877 by QueryMode ().
878
879 Returns:
880 EFI_SUCCESS - The operation completed successfully.
881 EFI_DEVICE_ERROR - The device had an error and
882 could not complete the request.
883 EFI_UNSUPPORTED - The output device is not in a valid text mode, or the
884 cursor position is invalid for the current mode.
885
886 --*/
887 {
888 //
889 // No need to do extra check here as whether (Column, Row) is valid has
890 // been checked in ConSplitterTextOutSetCursorPosition. And (0, 0) should
891 // always be supported.
892 //
893 Private->TextOutMode.CursorColumn = (INT32) Column;
894 Private->TextOutMode.CursorRow = (INT32) Row;
895
896 return EFI_SUCCESS;
897 }
898
899 EFI_STATUS
900 DevNullTextOutEnableCursor (
901 IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private,
902 IN BOOLEAN Visible
903 )
904 /*++
905 Routine Description:
906
907 Implements SIMPLE_TEXT_OUTPUT.EnableCursor().
908 In this driver, the cursor cannot be hidden.
909
910 Arguments:
911
912 Private - Indicates the calling context.
913
914 Visible - If TRUE, the cursor is set to be visible, If FALSE, the cursor
915 is set to be invisible.
916
917 Returns:
918
919 EFI_SUCCESS - The request is valid.
920
921
922 --*/
923 {
924 Private->TextOutMode.CursorVisible = Visible;
925
926 return EFI_SUCCESS;
927 }
928
929 EFI_STATUS
930 DevNullSyncUgaStdOut (
931 IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private
932 )
933 /*++
934 Routine Description:
935 Take the DevNull TextOut device and update the Simple Text Out on every
936 UGA device.
937
938 Arguments:
939 Private - Indicates the calling context.
940
941 Returns:
942 EFI_SUCCESS - The request is valid.
943 other - Return status of TextOut->OutputString ()
944
945 --*/
946 {
947 EFI_STATUS Status;
948 EFI_STATUS ReturnStatus;
949 UINTN Row;
950 UINTN Column;
951 UINTN List;
952 UINTN MaxColumn;
953 UINTN CurrentColumn;
954 UINTN StartRow;
955 UINTN StartColumn;
956 INT32 StartAttribute;
957 BOOLEAN StartCursorState;
958 CHAR16 *Screen;
959 CHAR16 *Str;
960 CHAR16 *Buffer;
961 CHAR16 *BufferTail;
962 CHAR16 *ScreenStart;
963 INT32 CurrentAttribute;
964 INT32 *Attributes;
965 EFI_SIMPLE_TEXT_OUT_PROTOCOL *Sto;
966
967 //
968 // Save the devices Attributes, Cursor enable state and location
969 //
970 StartColumn = Private->TextOutMode.CursorColumn;
971 StartRow = Private->TextOutMode.CursorRow;
972 StartAttribute = Private->TextOutMode.Attribute;
973 StartCursorState = Private->TextOutMode.CursorVisible;
974
975 for (List = 0; List < Private->CurrentNumberOfConsoles; List++) {
976
977 Sto = Private->TextOutList[List].TextOut;
978
979 //
980 // Skip non UGA devices
981 //
982 if (Private->TextOutList[List].UgaDraw != NULL) {
983 Sto->EnableCursor (Sto, FALSE);
984 Sto->ClearScreen (Sto);
985 }
986 }
987
988 ReturnStatus = EFI_SUCCESS;
989 Screen = Private->DevNullScreen;
990 Attributes = Private->DevNullAttributes;
991 MaxColumn = Private->DevNullColumns;
992
993 Buffer = AllocateZeroPool ((MaxColumn + 1) * sizeof (CHAR16));
994
995 for (Row = 0; Row < Private->DevNullRows; Row++, Screen += (MaxColumn + 1), Attributes += MaxColumn) {
996
997 if (Row == (Private->DevNullRows - 1)) {
998 //
999 // Don't ever sync the last character as it will scroll the screen
1000 //
1001 Screen[MaxColumn - 1] = 0x00;
1002 }
1003
1004 Column = 0;
1005 while (Column < MaxColumn) {
1006 if (Screen[Column]) {
1007 CurrentAttribute = Attributes[Column];
1008 CurrentColumn = Column;
1009 ScreenStart = &Screen[Column];
1010
1011 //
1012 // the line end is alway 0x0. So Column should be less than MaxColumn
1013 // It should be still in the same row
1014 //
1015 for (Str = ScreenStart, BufferTail = Buffer; *Str != 0; Str++, Column++) {
1016
1017 if (Attributes[Column] != CurrentAttribute) {
1018 Column--;
1019 break;
1020 }
1021
1022 *BufferTail = *Str;
1023 BufferTail++;
1024 if (Attributes[Column] & EFI_WIDE_ATTRIBUTE) {
1025 Str++;
1026 Column++;
1027 }
1028 }
1029
1030 *BufferTail = 0;
1031
1032 for (List = 0; List < Private->CurrentNumberOfConsoles; List++) {
1033
1034 Sto = Private->TextOutList[List].TextOut;
1035
1036 //
1037 // Skip non UGA devices
1038 //
1039 if (Private->TextOutList[List].UgaDraw != NULL) {
1040 Sto->SetAttribute (Sto, CurrentAttribute);
1041 Sto->SetCursorPosition (Sto, CurrentColumn, Row);
1042 Status = Sto->OutputString (Sto, Buffer);
1043 if (EFI_ERROR (Status)) {
1044 ReturnStatus = Status;
1045 }
1046 }
1047 }
1048
1049 }
1050
1051 Column++;
1052 }
1053 }
1054 //
1055 // Restore the devices Attributes, Cursor enable state and location
1056 //
1057 for (List = 0; List < Private->CurrentNumberOfConsoles; List++) {
1058 Sto = Private->TextOutList[List].TextOut;
1059
1060 //
1061 // Skip non UGA devices
1062 //
1063 if (Private->TextOutList[List].UgaDraw != NULL) {
1064 Sto->SetAttribute (Sto, StartAttribute);
1065 Sto->SetCursorPosition (Sto, StartColumn, StartRow);
1066 Status = Sto->EnableCursor (Sto, StartCursorState);
1067 if (EFI_ERROR (Status)) {
1068 ReturnStatus = Status;
1069 }
1070 }
1071 }
1072
1073 gBS->FreePool (Buffer);
1074
1075 return ReturnStatus;
1076 }