1 /*++ @file
2 
3 Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
4 Portions copyright (c) 2010,Apple Inc. All rights reserved.<BR>
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 
14 **/
15 
16 #include "Gop.h"
17 
18 
19 EFI_STATUS
FreeNotifyList(IN OUT LIST_ENTRY * ListHead)20 FreeNotifyList (
21   IN OUT LIST_ENTRY           *ListHead
22   )
23 /*++
24 
25 Routine Description:
26 
27 Arguments:
28 
29   ListHead   - The list head
30 
31 Returns:
32 
33   EFI_SUCCESS           - Free the notify list successfully
34   EFI_INVALID_PARAMETER - ListHead is invalid.
35 
36 **/
37 {
38   EMU_GOP_SIMPLE_TEXTIN_EX_NOTIFY *NotifyNode;
39 
40   if (ListHead == NULL) {
41     return EFI_INVALID_PARAMETER;
42   }
43   while (!IsListEmpty (ListHead)) {
44     NotifyNode = CR (
45                    ListHead->ForwardLink,
46                    EMU_GOP_SIMPLE_TEXTIN_EX_NOTIFY,
47                    NotifyEntry,
48                    EMU_GOP_SIMPLE_TEXTIN_EX_NOTIFY_SIGNATURE
49                    );
50     RemoveEntryList (ListHead->ForwardLink);
51     gBS->FreePool (NotifyNode);
52   }
53 
54   return EFI_SUCCESS;
55 }
56 
57 
58 /**
59   Tests to see if this driver supports a given controller. If a child device is provided,
60   it further tests to see if this driver supports creating a handle for the specified child device.
61 
62   This function checks to see if the driver specified by This supports the device specified by
63   ControllerHandle. Drivers will typically use the device path attached to
64   ControllerHandle and/or the services from the bus I/O abstraction attached to
65   ControllerHandle to determine if the driver supports ControllerHandle. This function
66   may be called many times during platform initialization. In order to reduce boot times, the tests
67   performed by this function must be very small, and take as little time as possible to execute. This
68   function must not change the state of any hardware devices, and this function must be aware that the
69   device specified by ControllerHandle may already be managed by the same driver or a
70   different driver. This function must match its calls to AllocatePages() with FreePages(),
71   AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
72   Because ControllerHandle may have been previously started by the same driver, if a protocol is
73   already in the opened state, then it must not be closed with CloseProtocol(). This is required
74   to guarantee the state of ControllerHandle is not modified by this function.
75 
76   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
77   @param[in]  ControllerHandle     The handle of the controller to test. This handle
78                                    must support a protocol interface that supplies
79                                    an I/O abstraction to the driver.
80   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
81                                    parameter is ignored by device drivers, and is optional for bus
82                                    drivers. For bus drivers, if this parameter is not NULL, then
83                                    the bus driver must determine if the bus controller specified
84                                    by ControllerHandle and the child controller specified
85                                    by RemainingDevicePath are both supported by this
86                                    bus driver.
87 
88   @retval EFI_SUCCESS              The device specified by ControllerHandle and
89                                    RemainingDevicePath is supported by the driver specified by This.
90   @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and
91                                    RemainingDevicePath is already being managed by the driver
92                                    specified by This.
93   @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and
94                                    RemainingDevicePath is already being managed by a different
95                                    driver or an application that requires exclusive access.
96                                    Currently not implemented.
97   @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
98                                    RemainingDevicePath is not supported by the driver specified by This.
99 **/
100 EFI_STATUS
101 EFIAPI
EmuGopDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Handle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)102 EmuGopDriverBindingSupported (
103   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
104   IN  EFI_HANDLE                      Handle,
105   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
106   )
107 {
108   EFI_STATUS              Status;
109   EMU_IO_THUNK_PROTOCOL   *EmuIoThunk;
110 
111   //
112   // Open the IO Abstraction(s) needed to perform the supported test
113   //
114   Status = gBS->OpenProtocol (
115                   Handle,
116                   &gEmuIoThunkProtocolGuid,
117                   (VOID **)&EmuIoThunk,
118                   This->DriverBindingHandle,
119                   Handle,
120                   EFI_OPEN_PROTOCOL_BY_DRIVER
121                   );
122   if (EFI_ERROR (Status)) {
123     return Status;
124   }
125 
126   Status = EmuGopSupported (EmuIoThunk);
127 
128   //
129   // Close the I/O Abstraction(s) used to perform the supported test
130   //
131   gBS->CloseProtocol (
132         Handle,
133         &gEmuIoThunkProtocolGuid,
134         This->DriverBindingHandle,
135         Handle
136         );
137 
138   return Status;
139 }
140 
141 
142 /**
143   Starts a device controller or a bus controller.
144 
145   The Start() function is designed to be invoked from the EFI boot service ConnectController().
146   As a result, much of the error checking on the parameters to Start() has been moved into this
147   common boot service. It is legal to call Start() from other locations,
148   but the following calling restrictions must be followed, or the system behavior will not be deterministic.
149   1. ControllerHandle must be a valid EFI_HANDLE.
150   2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
151      EFI_DEVICE_PATH_PROTOCOL.
152   3. Prior to calling Start(), the Supported() function for the driver specified by This must
153      have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
154 
155   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
156   @param[in]  ControllerHandle     The handle of the controller to start. This handle
157                                    must support a protocol interface that supplies
158                                    an I/O abstraction to the driver.
159   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
160                                    parameter is ignored by device drivers, and is optional for bus
161                                    drivers. For a bus driver, if this parameter is NULL, then handles
162                                    for all the children of Controller are created by this driver.
163                                    If this parameter is not NULL and the first Device Path Node is
164                                    not the End of Device Path Node, then only the handle for the
165                                    child device specified by the first Device Path Node of
166                                    RemainingDevicePath is created by this driver.
167                                    If the first Device Path Node of RemainingDevicePath is
168                                    the End of Device Path Node, no child handle is created by this
169                                    driver.
170 
171   @retval EFI_SUCCESS              The device was started.
172   @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.
173   @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
174   @retval Others                   The driver failded to start the device.
175 
176 **/
177 EFI_STATUS
178 EFIAPI
EmuGopDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Handle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)179 EmuGopDriverBindingStart (
180   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
181   IN  EFI_HANDLE                      Handle,
182   IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
183   )
184 {
185   EMU_IO_THUNK_PROTOCOL   *EmuIoThunk;
186   EFI_STATUS              Status;
187   GOP_PRIVATE_DATA        *Private;
188 
189   //
190   // Grab the protocols we need
191   //
192   Status = gBS->OpenProtocol (
193                   Handle,
194                   &gEmuIoThunkProtocolGuid,
195                   (VOID **)&EmuIoThunk,
196                   This->DriverBindingHandle,
197                   Handle,
198                   EFI_OPEN_PROTOCOL_BY_DRIVER
199                   );
200   if (EFI_ERROR (Status)) {
201     return EFI_UNSUPPORTED;
202   }
203 
204   //
205   // Allocate Private context data for SGO inteface.
206   //
207   Private = NULL;
208   Status = gBS->AllocatePool (
209                   EfiBootServicesData,
210                   sizeof (GOP_PRIVATE_DATA),
211                   (VOID **)&Private
212                   );
213   if (EFI_ERROR (Status)) {
214     goto Done;
215   }
216   //
217   // Set up context record
218   //
219   Private->Signature           = GOP_PRIVATE_DATA_SIGNATURE;
220   Private->Handle              = Handle;
221   Private->EmuIoThunk          = EmuIoThunk;
222   Private->WindowName          = EmuIoThunk->ConfigString;
223   Private->ControllerNameTable = NULL;
224 
225   AddUnicodeString (
226     "eng",
227     gEmuGopComponentName.SupportedLanguages,
228     &Private->ControllerNameTable,
229     EmuIoThunk->ConfigString
230     );
231   AddUnicodeString2 (
232     "en",
233     gEmuGopComponentName2.SupportedLanguages,
234     &Private->ControllerNameTable,
235     EmuIoThunk->ConfigString,
236     FALSE
237     );
238 
239   Status = EmuGopConstructor (Private);
240   if (EFI_ERROR (Status)) {
241     goto Done;
242   }
243   //
244   // Publish the Gop interface to the world
245   //
246   Status = gBS->InstallMultipleProtocolInterfaces (
247                   &Private->Handle,
248                   &gEfiGraphicsOutputProtocolGuid,    &Private->GraphicsOutput,
249                   &gEfiSimpleTextInProtocolGuid,      &Private->SimpleTextIn,
250                   &gEfiSimplePointerProtocolGuid,     &Private->SimplePointer,
251                   &gEfiSimpleTextInputExProtocolGuid, &Private->SimpleTextInEx,
252                   NULL
253                   );
254 
255 Done:
256   if (EFI_ERROR (Status)) {
257 
258     gBS->CloseProtocol (
259           Handle,
260           &gEmuIoThunkProtocolGuid,
261           This->DriverBindingHandle,
262           Handle
263           );
264 
265     if (Private != NULL) {
266       //
267       // On Error Free back private data
268       //
269       if (Private->ControllerNameTable != NULL) {
270         FreeUnicodeStringTable (Private->ControllerNameTable);
271       }
272       if (Private->SimpleTextIn.WaitForKey != NULL) {
273         gBS->CloseEvent (Private->SimpleTextIn.WaitForKey);
274       }
275       if (Private->SimpleTextInEx.WaitForKeyEx != NULL) {
276         gBS->CloseEvent (Private->SimpleTextInEx.WaitForKeyEx);
277       }
278       FreeNotifyList (&Private->NotifyList);
279 
280       gBS->FreePool (Private);
281     }
282   }
283 
284   return Status;
285 }
286 
287 
288 
289 /**
290   Stops a device controller or a bus controller.
291 
292   The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
293   As a result, much of the error checking on the parameters to Stop() has been moved
294   into this common boot service. It is legal to call Stop() from other locations,
295   but the following calling restrictions must be followed, or the system behavior will not be deterministic.
296   1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
297      same driver's Start() function.
298   2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
299      EFI_HANDLE. In addition, all of these handles must have been created in this driver's
300      Start() function, and the Start() function must have called OpenProtocol() on
301      ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
302 
303   @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
304   @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
305                                 support a bus specific I/O protocol for the driver
306                                 to use to stop the device.
307   @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
308   @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
309                                 if NumberOfChildren is 0.
310 
311   @retval EFI_SUCCESS           The device was stopped.
312   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
313 
314 **/
315 EFI_STATUS
316 EFIAPI
EmuGopDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Handle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)317 EmuGopDriverBindingStop (
318   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
319   IN  EFI_HANDLE                   Handle,
320   IN  UINTN                        NumberOfChildren,
321   IN  EFI_HANDLE                   *ChildHandleBuffer
322   )
323 {
324   EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
325   EFI_STATUS                   Status;
326   GOP_PRIVATE_DATA             *Private;
327 
328   Status = gBS->OpenProtocol (
329                   Handle,
330                   &gEfiGraphicsOutputProtocolGuid,
331                   (VOID **)&GraphicsOutput,
332                   This->DriverBindingHandle,
333                   Handle,
334                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
335                   );
336   if (EFI_ERROR (Status)) {
337     //
338     // If the GOP interface does not exist the driver is not started
339     //
340     return EFI_NOT_STARTED;
341   }
342 
343   //
344   // Get our private context information
345   //
346   Private = GOP_PRIVATE_DATA_FROM_THIS (GraphicsOutput);
347 
348   //
349   // Remove the SGO interface from the system
350   //
351   Status = gBS->UninstallMultipleProtocolInterfaces (
352                   Private->Handle,
353                   &gEfiGraphicsOutputProtocolGuid,    &Private->GraphicsOutput,
354                   &gEfiSimpleTextInProtocolGuid,      &Private->SimpleTextIn,
355                   &gEfiSimplePointerProtocolGuid,     &Private->SimplePointer,
356                   &gEfiSimpleTextInputExProtocolGuid, &Private->SimpleTextInEx,
357                   NULL
358                   );
359   if (!EFI_ERROR (Status)) {
360     //
361     // Shutdown the hardware
362     //
363     Status = EmuGopDestructor (Private);
364     if (EFI_ERROR (Status)) {
365       return EFI_DEVICE_ERROR;
366     }
367 
368     gBS->CloseProtocol (
369           Handle,
370           &gEmuIoThunkProtocolGuid,
371           This->DriverBindingHandle,
372           Handle
373           );
374 
375     //
376     // Free our instance data
377     //
378     FreeUnicodeStringTable (Private->ControllerNameTable);
379 
380     Status = gBS->CloseEvent (Private->SimpleTextIn.WaitForKey);
381     ASSERT_EFI_ERROR (Status);
382 
383     Status = gBS->CloseEvent (Private->SimpleTextInEx.WaitForKeyEx);
384     ASSERT_EFI_ERROR (Status);
385 
386     FreeNotifyList (&Private->NotifyList);
387 
388     gBS->FreePool (Private);
389 
390   }
391 
392   return Status;
393 }
394 
395 
396 ///
397 /// This protocol provides the services required to determine if a driver supports a given controller.
398 /// If a controller is supported, then it also provides routines to start and stop the controller.
399 ///
400 EFI_DRIVER_BINDING_PROTOCOL gEmuGopDriverBinding = {
401   EmuGopDriverBindingSupported,
402   EmuGopDriverBindingStart,
403   EmuGopDriverBindingStop,
404   0xa,
405   NULL,
406   NULL
407 };
408 
409 
410 
411 /**
412   The user Entry Point for module EmuGop. The user code starts with this function.
413 
414   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
415   @param[in] SystemTable    A pointer to the EFI System Table.
416 
417   @retval EFI_SUCCESS       The entry point is executed successfully.
418   @retval other             Some error occurs when executing this entry point.
419 
420 **/
421 EFI_STATUS
422 EFIAPI
InitializeEmuGop(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)423 InitializeEmuGop (
424   IN EFI_HANDLE           ImageHandle,
425   IN EFI_SYSTEM_TABLE     *SystemTable
426   )
427 {
428   EFI_STATUS              Status;
429 
430   Status = EfiLibInstallDriverBindingComponentName2 (
431              ImageHandle,
432              SystemTable,
433              &gEmuGopDriverBinding,
434              ImageHandle,
435              &gEmuGopComponentName,
436              &gEmuGopComponentName2
437              );
438   ASSERT_EFI_ERROR (Status);
439 
440 
441   return Status;
442 }
443 
444