GopDriver.c revision d18d8a1d0e370f8ce6ccc2725f4170586d457e53
1/*++ @file
2
3Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
4Portions copyright (c) 2010,Apple Inc. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution.  The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13
14**/
15
16#include "Gop.h"
17
18
19EFI_STATUS
20FreeNotifyList (
21  IN OUT LIST_ENTRY           *ListHead
22  )
23/*++
24
25Routine Description:
26
27Arguments:
28
29  ListHead   - The list head
30
31Returns:
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**/
100EFI_STATUS
101EFIAPI
102EmuGopDriverBindingSupported (
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**/
177EFI_STATUS
178EFIAPI
179EmuGopDriverBindingStart (
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
255Done:
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**/
315EFI_STATUS
316EFIAPI
317EmuGopDriverBindingStop (
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///
400EFI_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**/
421EFI_STATUS
422EFIAPI
423InitializeEmuGop (
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