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 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 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 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 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 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