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