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