1 /*++ @file
2 
3 Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
4 Portions copyright (c) 2010 - 2011, Apple Inc. All rights reserved.
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution.  The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9 
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 Module Name:
14 
15     EmuGopScreen.c
16 
17 Abstract:
18 
19   This file produces the graphics abstration of UGA. It is called by
20   EmuGopDriver.c file which deals with the EFI 1.1 driver model.
21   This file just does graphics.
22 
23 **/
24 
25 #include "Gop.h"
26 
27 
28 EFI_EVENT               mGopScreenExitBootServicesEvent;
29 
30 GOP_MODE_DATA mGopModeData[] = {
31     { 800,  600, 0, 0 },
32     { 640,  480, 0, 0 },
33     { 720,  400, 0, 0 },
34     {1024,  768, 0, 0 },
35     {1280, 1024, 0, 0 }
36     };
37 
38 
39 /**
40   Returns information for an available graphics mode that the graphics device
41   and the set of active video output devices supports.
42 
43   @param  This                  The EFI_GRAPHICS_OUTPUT_PROTOCOL instance.
44   @param  ModeNumber            The mode number to return information on.
45   @param  SizeOfInfo            A pointer to the size, in bytes, of the Info buffer.
46   @param  Info                  A pointer to callee allocated buffer that returns information about ModeNumber.
47 
48   @retval EFI_SUCCESS           Mode information returned.
49   @retval EFI_BUFFER_TOO_SMALL  The Info buffer was too small.
50   @retval EFI_DEVICE_ERROR      A hardware error occurred trying to retrieve the video mode.
51   @retval EFI_NOT_STARTED       Video display is not initialized. Call SetMode ()
52   @retval EFI_INVALID_PARAMETER One of the input args was NULL.
53 
54 **/
55 EFI_STATUS
56 EFIAPI
EmuGopQuerytMode(IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,IN UINT32 ModeNumber,OUT UINTN * SizeOfInfo,OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION ** Info)57 EmuGopQuerytMode (
58   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL          *This,
59   IN  UINT32                                ModeNumber,
60   OUT UINTN                                 *SizeOfInfo,
61   OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  **Info
62   )
63 {
64   GOP_PRIVATE_DATA  *Private;
65 
66   Private = GOP_PRIVATE_DATA_FROM_THIS (This);
67 
68   if (Info == NULL || SizeOfInfo == NULL || (UINTN) ModeNumber >= This->Mode->MaxMode) {
69     return EFI_INVALID_PARAMETER;
70   }
71 
72   *Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
73   if (*Info == NULL) {
74     return EFI_OUT_OF_RESOURCES;
75   }
76 
77   *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
78 
79   (*Info)->Version = 0;
80   (*Info)->HorizontalResolution = Private->ModeData[ModeNumber].HorizontalResolution;
81   (*Info)->VerticalResolution   = Private->ModeData[ModeNumber].VerticalResolution;
82   (*Info)->PixelFormat = PixelBltOnly;
83   (*Info)->PixelsPerScanLine = (*Info)->HorizontalResolution;
84 
85   return EFI_SUCCESS;
86 }
87 
88 
89 
90 /**
91   Set the video device into the specified mode and clears the visible portions of
92   the output display to black.
93 
94   @param  This              The EFI_GRAPHICS_OUTPUT_PROTOCOL instance.
95   @param  ModeNumber        Abstraction that defines the current video mode.
96 
97   @retval EFI_SUCCESS       The graphics mode specified by ModeNumber was selected.
98   @retval EFI_DEVICE_ERROR  The device had an error and could not complete the request.
99   @retval EFI_UNSUPPORTED   ModeNumber is not supported by this device.
100 
101 **/
102 EFI_STATUS
103 EFIAPI
EmuGopSetMode(IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,IN UINT32 ModeNumber)104 EmuGopSetMode (
105   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL  *This,
106   IN  UINT32                        ModeNumber
107   )
108 {
109   EFI_STATUS                      Status;
110   GOP_PRIVATE_DATA                *Private;
111   GOP_MODE_DATA                   *ModeData;
112   EFI_GRAPHICS_OUTPUT_BLT_PIXEL   Fill;
113 
114   Private = GOP_PRIVATE_DATA_FROM_THIS (This);
115 
116   if (ModeNumber >= This->Mode->MaxMode) {
117     return EFI_UNSUPPORTED;
118   }
119 
120   ModeData = &Private->ModeData[ModeNumber];
121   This->Mode->Mode = ModeNumber;
122   Private->GraphicsOutput.Mode->Info->HorizontalResolution = ModeData->HorizontalResolution;
123   Private->GraphicsOutput.Mode->Info->VerticalResolution = ModeData->VerticalResolution;
124   Private->GraphicsOutput.Mode->Info->PixelsPerScanLine = ModeData->HorizontalResolution;
125 
126   if (Private->HardwareNeedsStarting) {
127     Status = EmuGopStartWindow (
128               Private,
129               ModeData->HorizontalResolution,
130               ModeData->VerticalResolution,
131               ModeData->ColorDepth,
132               ModeData->RefreshRate
133               );
134     if (EFI_ERROR (Status)) {
135       return EFI_DEVICE_ERROR;
136     }
137 
138     Private->HardwareNeedsStarting = FALSE;
139   }
140 
141 
142   Status = Private->EmuGraphicsWindow->Size(
143                             Private->EmuGraphicsWindow,
144                             ModeData->HorizontalResolution,
145                             ModeData->VerticalResolution
146                             );
147 
148 
149   Fill.Red                      = 0x7f;
150   Fill.Green                    = 0x7F;
151   Fill.Blue                     = 0x7f;
152   This->Blt (
153           This,
154           &Fill,
155           EfiBltVideoFill,
156           0,
157           0,
158           0,
159           0,
160           ModeData->HorizontalResolution,
161           ModeData->VerticalResolution,
162           ModeData->HorizontalResolution * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
163           );
164   return EFI_SUCCESS;
165 }
166 
167 
168 
169 /**
170   Blt a rectangle of pixels on the graphics screen. Blt stands for BLock Transfer.
171 
172   @param  This         Protocol instance pointer.
173   @param  BltBuffer    Buffer containing data to blit into video buffer. This
174                        buffer has a size of Width*Height*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
175   @param  BltOperation Operation to perform on BlitBuffer and video memory
176   @param  SourceX      X coordinate of source for the BltBuffer.
177   @param  SourceY      Y coordinate of source for the BltBuffer.
178   @param  DestinationX X coordinate of destination for the BltBuffer.
179   @param  DestinationY Y coordinate of destination for the BltBuffer.
180   @param  Width        Width of rectangle in BltBuffer in pixels.
181   @param  Height       Hight of rectangle in BltBuffer in pixels.
182   @param  Delta        OPTIONAL
183 
184   @retval EFI_SUCCESS           The Blt operation completed.
185   @retval EFI_INVALID_PARAMETER BltOperation is not valid.
186   @retval EFI_DEVICE_ERROR      A hardware error occured writting to the video buffer.
187 
188 **/
189 EFI_STATUS
190 EFIAPI
EmuGopBlt(IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL * BltBuffer,OPTIONAL IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,IN UINTN SourceX,IN UINTN SourceY,IN UINTN DestinationX,IN UINTN DestinationY,IN UINTN Width,IN UINTN Height,IN UINTN Delta OPTIONAL)191 EmuGopBlt (
192   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL            *This,
193   IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL           *BltBuffer,   OPTIONAL
194   IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION       BltOperation,
195   IN  UINTN                                   SourceX,
196   IN  UINTN                                   SourceY,
197   IN  UINTN                                   DestinationX,
198   IN  UINTN                                   DestinationY,
199   IN  UINTN                                   Width,
200   IN  UINTN                                   Height,
201   IN  UINTN                                   Delta         OPTIONAL
202   )
203 {
204   GOP_PRIVATE_DATA  *Private;
205   EFI_TPL           OriginalTPL;
206   EFI_STATUS        Status;
207   EMU_GRAPHICS_WINDOWS__BLT_ARGS      GopBltArgs;
208 
209   Private = GOP_PRIVATE_DATA_FROM_THIS (This);
210 
211   if ((UINT32)BltOperation >= EfiGraphicsOutputBltOperationMax) {
212     return EFI_INVALID_PARAMETER;
213   }
214 
215   if (Width == 0 || Height == 0) {
216     return EFI_INVALID_PARAMETER;
217   }
218   //
219   // If Delta is zero, then the entire BltBuffer is being used, so Delta
220   // is the number of bytes in each row of BltBuffer.  Since BltBuffer is Width pixels size,
221   // the number of bytes in each row can be computed.
222   //
223   if (Delta == 0) {
224     Delta = Width * sizeof (EFI_UGA_PIXEL);
225   }
226 
227   //
228   // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
229   // We would not want a timer based event (Cursor, ...) to come in while we are
230   // doing this operation.
231   //
232   OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
233 
234   //
235   // Pack UGA Draw protocol parameters to EMU_GRAPHICS_WINDOWS__BLT_ARGS structure to adapt to
236   // GopBlt() API of Unix UGA IO protocol.
237   //
238   GopBltArgs.DestinationX = DestinationX;
239   GopBltArgs.DestinationY = DestinationY;
240   GopBltArgs.Height       = Height;
241   GopBltArgs.Width        = Width;
242   GopBltArgs.SourceX      = SourceX;
243   GopBltArgs.SourceY      = SourceY;
244   GopBltArgs.Delta        = Delta;
245   Status = Private->EmuGraphicsWindow->Blt (
246                             Private->EmuGraphicsWindow,
247                             (EFI_UGA_PIXEL *)BltBuffer,
248                             (EFI_UGA_BLT_OPERATION)BltOperation,
249                             &GopBltArgs
250                             );
251 
252   gBS->RestoreTPL (OriginalTPL);
253 
254   return Status;
255 }
256 
257 
258 //
259 // Construction and Destruction functions
260 //
261 
262 EFI_STATUS
EmuGopSupported(IN EMU_IO_THUNK_PROTOCOL * EmuIoThunk)263 EmuGopSupported (
264   IN  EMU_IO_THUNK_PROTOCOL  *EmuIoThunk
265   )
266 {
267   //
268   // Check to see if the IO abstraction represents a device type we support.
269   //
270   // This would be replaced a check of PCI subsystem ID, etc.
271   //
272   if (!CompareGuid (EmuIoThunk->Protocol, &gEmuGraphicsWindowProtocolGuid)) {
273     return EFI_UNSUPPORTED;
274   }
275 
276   return EFI_SUCCESS;
277 }
278 
279 
280 EFI_STATUS
EmuGopStartWindow(IN GOP_PRIVATE_DATA * Private,IN UINT32 HorizontalResolution,IN UINT32 VerticalResolution,IN UINT32 ColorDepth,IN UINT32 RefreshRate)281 EmuGopStartWindow (
282   IN  GOP_PRIVATE_DATA    *Private,
283   IN  UINT32              HorizontalResolution,
284   IN  UINT32              VerticalResolution,
285   IN  UINT32              ColorDepth,
286   IN  UINT32              RefreshRate
287   )
288 {
289   EFI_STATUS          Status;
290 
291   //
292   // Register to be notified on exit boot services so we can destroy the window.
293   //
294   Status = gBS->CreateEvent (
295                   EVT_SIGNAL_EXIT_BOOT_SERVICES,
296                   TPL_CALLBACK,
297                   ShutdownGopEvent,
298                   Private,
299                   &mGopScreenExitBootServicesEvent
300                   );
301 
302   Status = Private->EmuIoThunk->Open (Private->EmuIoThunk);
303   if (!EFI_ERROR (Status)) {
304     Private->EmuGraphicsWindow = Private->EmuIoThunk->Interface;
305 
306     // Register callback to support RegisterKeyNotify()
307     Status  = Private->EmuGraphicsWindow->RegisterKeyNotify (
308                                             Private->EmuGraphicsWindow,
309                                             GopPrivateMakeCallbackFunction,
310                                             GopPrivateBreakCallbackFunction,
311                                             Private
312                                             );
313     ASSERT_EFI_ERROR (Status);
314   }
315   return Status;
316 }
317 
318 EFI_STATUS
EmuGopConstructor(GOP_PRIVATE_DATA * Private)319 EmuGopConstructor (
320   GOP_PRIVATE_DATA    *Private
321   )
322 {
323   Private->ModeData = mGopModeData;
324 
325   Private->GraphicsOutput.QueryMode      = EmuGopQuerytMode;
326   Private->GraphicsOutput.SetMode        = EmuGopSetMode;
327   Private->GraphicsOutput.Blt            = EmuGopBlt;
328 
329   //
330   // Allocate buffer for Graphics Output Protocol mode information
331   //
332   Private->GraphicsOutput.Mode = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE));
333   if (Private->GraphicsOutput.Mode == NULL) {
334     return EFI_OUT_OF_RESOURCES;
335   }
336   Private->GraphicsOutput.Mode->Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
337   if (Private->GraphicsOutput.Mode->Info == NULL) {
338     return EFI_OUT_OF_RESOURCES;
339   }
340 
341   Private->GraphicsOutput.Mode->MaxMode = sizeof(mGopModeData) / sizeof(GOP_MODE_DATA);
342   //
343   // Till now, we have no idea about the window size.
344   //
345   Private->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;
346   Private->GraphicsOutput.Mode->Info->Version = 0;
347   Private->GraphicsOutput.Mode->Info->HorizontalResolution = 0;
348   Private->GraphicsOutput.Mode->Info->VerticalResolution = 0;
349   Private->GraphicsOutput.Mode->Info->PixelFormat = PixelBltOnly;
350   Private->GraphicsOutput.Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
351   Private->GraphicsOutput.Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL;
352   Private->GraphicsOutput.Mode->FrameBufferSize = 0;
353 
354   Private->HardwareNeedsStarting  = TRUE;
355   Private->EmuGraphicsWindow                  = NULL;
356 
357   EmuGopInitializeSimpleTextInForWindow (Private);
358 
359   EmuGopInitializeSimplePointerForWindow (Private);
360 
361   return EFI_SUCCESS;
362 }
363 
364 
365 
366 EFI_STATUS
EmuGopDestructor(GOP_PRIVATE_DATA * Private)367 EmuGopDestructor (
368   GOP_PRIVATE_DATA     *Private
369   )
370 {
371   if (!Private->HardwareNeedsStarting) {
372     Private->EmuIoThunk->Close (Private->EmuIoThunk);
373     Private->EmuGraphicsWindow = NULL;
374   }
375 
376   //
377   // Free graphics output protocol occupied resource
378   //
379   if (Private->GraphicsOutput.Mode != NULL) {
380     if (Private->GraphicsOutput.Mode->Info != NULL) {
381       FreePool (Private->GraphicsOutput.Mode->Info);
382     }
383     FreePool (Private->GraphicsOutput.Mode);
384   }
385 
386   return EFI_SUCCESS;
387 }
388 
389 
390 VOID
391 EFIAPI
ShutdownGopEvent(IN EFI_EVENT Event,IN VOID * Context)392 ShutdownGopEvent (
393   IN EFI_EVENT  Event,
394   IN VOID       *Context
395   )
396 /*++
397 
398 Routine Description:
399 
400   This is the UGA screen's callback notification function for exit-boot-services.
401   All we do here is call EmuGopDestructor().
402 
403 Arguments:
404 
405   Event   - not used
406   Context - pointer to the Private structure.
407 
408 Returns:
409 
410   None.
411 
412 **/
413 {
414   EmuGopDestructor (Context);
415 }
416 
417