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