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