1 /** @file 2 Emu Bus driver 3 4 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> 5 Portions copyright (c) 2011, Apple Inc. All rights reserved. 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 15 **/ 16 17 #include "EmuBusDriverDxe.h" 18 19 20 21 // 22 // DriverBinding protocol global 23 // 24 EFI_DRIVER_BINDING_PROTOCOL gEmuBusDriverBinding = { 25 EmuBusDriverBindingSupported, 26 EmuBusDriverBindingStart, 27 EmuBusDriverBindingStop, 28 0xa, 29 NULL, 30 NULL 31 }; 32 33 34 35 EFI_STATUS 36 EFIAPI 37 EmuBusDriverBindingSupported ( 38 IN EFI_DRIVER_BINDING_PROTOCOL *This, 39 IN EFI_HANDLE ControllerHandle, 40 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 41 ) 42 { 43 EFI_STATUS Status; 44 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; 45 EMU_THUNK_PROTOCOL *EmuThunk; 46 47 // 48 // Check the contents of the first Device Path Node of RemainingDevicePath to make sure 49 // it is a legal Device Path Node for this bus driver's children. 50 // 51 if (RemainingDevicePath != NULL) { 52 // 53 // Check if RemainingDevicePath is the End of Device Path Node, 54 // if yes, go on checking other conditions 55 // 56 if (!IsDevicePathEnd (RemainingDevicePath)) { 57 // 58 // If RemainingDevicePath isn't the End of Device Path Node, 59 // check its validation 60 // 61 if (RemainingDevicePath->Type != HARDWARE_DEVICE_PATH || 62 RemainingDevicePath->SubType != HW_VENDOR_DP || 63 DevicePathNodeLength(RemainingDevicePath) != sizeof(EMU_VENDOR_DEVICE_PATH_NODE)) { 64 return EFI_UNSUPPORTED; 65 } 66 } 67 } 68 69 // 70 // Open the IO Abstraction(s) needed to perform the supported test 71 // 72 Status = gBS->OpenProtocol ( 73 ControllerHandle, 74 &gEmuThunkProtocolGuid, 75 (VOID **)&EmuThunk , 76 This->DriverBindingHandle, 77 ControllerHandle, 78 EFI_OPEN_PROTOCOL_BY_DRIVER 79 ); 80 if (Status == EFI_ALREADY_STARTED) { 81 return EFI_SUCCESS; 82 } 83 84 if (EFI_ERROR (Status)) { 85 return Status; 86 } 87 88 // 89 // Close the I/O Abstraction(s) used to perform the supported test 90 // 91 gBS->CloseProtocol ( 92 ControllerHandle, 93 &gEmuThunkProtocolGuid, 94 This->DriverBindingHandle, 95 ControllerHandle 96 ); 97 98 // 99 // Open the EFI Device Path protocol needed to perform the supported test 100 // 101 Status = gBS->OpenProtocol ( 102 ControllerHandle, 103 &gEfiDevicePathProtocolGuid, 104 (VOID **)&ParentDevicePath, 105 This->DriverBindingHandle, 106 ControllerHandle, 107 EFI_OPEN_PROTOCOL_BY_DRIVER 108 ); 109 if (Status == EFI_ALREADY_STARTED) { 110 return EFI_SUCCESS; 111 } 112 113 if (EFI_ERROR (Status)) { 114 return Status; 115 } 116 117 118 // 119 // Close protocol, don't use device path protocol in the Support() function 120 // 121 gBS->CloseProtocol ( 122 ControllerHandle, 123 &gEfiDevicePathProtocolGuid, 124 This->DriverBindingHandle, 125 ControllerHandle 126 ); 127 128 return Status; 129 } 130 131 132 EFI_STATUS 133 EFIAPI 134 EmuBusDriverBindingStart ( 135 IN EFI_DRIVER_BINDING_PROTOCOL *This, 136 IN EFI_HANDLE ControllerHandle, 137 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 138 ) 139 { 140 EFI_STATUS Status; 141 EFI_STATUS InstallStatus; 142 EMU_THUNK_PROTOCOL *EmuThunk; 143 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; 144 EMU_IO_DEVICE *EmuDevice; 145 EMU_BUS_DEVICE *EmuBusDevice; 146 EMU_IO_THUNK_PROTOCOL *EmuIoThunk; 147 UINT16 ComponentName[512]; 148 EMU_VENDOR_DEVICE_PATH_NODE *Node; 149 BOOLEAN CreateDevice; 150 151 InstallStatus = EFI_UNSUPPORTED; 152 Status = EFI_UNSUPPORTED; 153 154 // 155 // Grab the protocols we need 156 // 157 Status = gBS->OpenProtocol ( 158 ControllerHandle, 159 &gEfiDevicePathProtocolGuid, 160 (VOID **)&ParentDevicePath, 161 This->DriverBindingHandle, 162 ControllerHandle, 163 EFI_OPEN_PROTOCOL_BY_DRIVER 164 ); 165 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { 166 return Status; 167 } 168 169 Status = gBS->OpenProtocol ( 170 ControllerHandle, 171 &gEmuThunkProtocolGuid, 172 (VOID **)&EmuThunk, 173 This->DriverBindingHandle, 174 ControllerHandle, 175 EFI_OPEN_PROTOCOL_BY_DRIVER 176 ); 177 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { 178 return Status; 179 } 180 181 if (Status != EFI_ALREADY_STARTED) { 182 EmuBusDevice = AllocatePool (sizeof (EMU_BUS_DEVICE)); 183 if (EmuBusDevice == NULL) { 184 return EFI_OUT_OF_RESOURCES; 185 } 186 187 EmuBusDevice->Signature = EMU_BUS_DEVICE_SIGNATURE; 188 EmuBusDevice->ControllerNameTable = NULL; 189 190 AddUnicodeString2 ( 191 "eng", 192 gEmuBusDriverComponentName.SupportedLanguages, 193 &EmuBusDevice->ControllerNameTable, 194 L"Emulator Bus Controller", 195 TRUE 196 ); 197 AddUnicodeString2 ( 198 "en", 199 gEmuBusDriverComponentName2.SupportedLanguages, 200 &EmuBusDevice->ControllerNameTable, 201 L"Emulator Bus Controller", 202 FALSE 203 ); 204 205 206 Status = gBS->InstallMultipleProtocolInterfaces ( 207 &ControllerHandle, 208 &gEfiCallerIdGuid, EmuBusDevice, 209 NULL 210 ); 211 if (EFI_ERROR (Status)) { 212 FreeUnicodeStringTable (EmuBusDevice->ControllerNameTable); 213 gBS->FreePool (EmuBusDevice); 214 return Status; 215 } 216 } 217 218 219 for (Status = EFI_SUCCESS, EmuIoThunk = NULL; !EFI_ERROR (Status); ) { 220 Status = EmuThunk->GetNextProtocol (TRUE, &EmuIoThunk); 221 if (EFI_ERROR (Status)) { 222 break; 223 } 224 225 CreateDevice = TRUE; 226 if (RemainingDevicePath != NULL) { 227 CreateDevice = FALSE; 228 // 229 // Check if RemainingDevicePath is the End of Device Path Node, 230 // if yes, don't create any child device 231 // 232 if (!IsDevicePathEnd (RemainingDevicePath)) { 233 // 234 // If RemainingDevicePath isn't the End of Device Path Node, 235 // check its validation 236 // 237 Node = (EMU_VENDOR_DEVICE_PATH_NODE *) RemainingDevicePath; 238 if (Node->VendorDevicePath.Header.Type == HARDWARE_DEVICE_PATH && 239 Node->VendorDevicePath.Header.SubType == HW_VENDOR_DP && 240 DevicePathNodeLength (&Node->VendorDevicePath.Header) == sizeof (EMU_VENDOR_DEVICE_PATH_NODE) 241 ) { 242 if (CompareGuid (&Node->VendorDevicePath.Guid, EmuIoThunk->Protocol) && Node->Instance == EmuIoThunk->Instance) { 243 CreateDevice = TRUE; 244 } 245 } 246 } 247 } 248 249 if (CreateDevice) { 250 // 251 // Allocate instance structure, and fill in parent information. 252 // 253 EmuDevice = AllocatePool (sizeof (EMU_IO_DEVICE)); 254 if (EmuDevice == NULL) { 255 return EFI_OUT_OF_RESOURCES; 256 } 257 258 EmuDevice->Handle = NULL; 259 EmuDevice->ControllerHandle = ControllerHandle; 260 EmuDevice->ParentDevicePath = ParentDevicePath; 261 CopyMem (&EmuDevice->EmuIoThunk, EmuIoThunk, sizeof (EMU_IO_THUNK_PROTOCOL)); 262 263 EmuDevice->ControllerNameTable = NULL; 264 265 StrnCpy (ComponentName, EmuIoThunk->ConfigString, sizeof (ComponentName)/sizeof (CHAR16)); 266 267 EmuDevice->DevicePath = EmuBusCreateDevicePath ( 268 ParentDevicePath, 269 EmuIoThunk->Protocol, 270 EmuIoThunk->Instance 271 ); 272 if (EmuDevice->DevicePath == NULL) { 273 gBS->FreePool (EmuDevice); 274 return EFI_OUT_OF_RESOURCES; 275 } 276 277 AddUnicodeString ( 278 "eng", 279 gEmuBusDriverComponentName.SupportedLanguages, 280 &EmuDevice->ControllerNameTable, 281 ComponentName 282 ); 283 284 EmuDevice->Signature = EMU_IO_DEVICE_SIGNATURE; 285 286 InstallStatus = gBS->InstallMultipleProtocolInterfaces ( 287 &EmuDevice->Handle, 288 &gEfiDevicePathProtocolGuid, EmuDevice->DevicePath, 289 &gEmuIoThunkProtocolGuid, &EmuDevice->EmuIoThunk, 290 NULL 291 ); 292 if (EFI_ERROR (InstallStatus)) { 293 FreeUnicodeStringTable (EmuDevice->ControllerNameTable); 294 gBS->FreePool (EmuDevice); 295 } else { 296 // 297 // Open For Child Device 298 // 299 Status = gBS->OpenProtocol ( 300 ControllerHandle, 301 &gEmuThunkProtocolGuid, 302 (VOID **)&EmuThunk , 303 This->DriverBindingHandle, 304 EmuDevice->Handle, 305 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 306 ); 307 if (!EFI_ERROR (Status)) { 308 InstallStatus = EFI_SUCCESS; 309 } 310 } 311 } 312 } 313 314 return InstallStatus; 315 } 316 317 318 EFI_STATUS 319 EFIAPI 320 EmuBusDriverBindingStop ( 321 IN EFI_DRIVER_BINDING_PROTOCOL *This, 322 IN EFI_HANDLE ControllerHandle, 323 IN UINTN NumberOfChildren, 324 IN EFI_HANDLE *ChildHandleBuffer 325 ) 326 { 327 EFI_STATUS Status; 328 UINTN Index; 329 BOOLEAN AllChildrenStopped; 330 EMU_IO_THUNK_PROTOCOL *EmuIoThunk; 331 EMU_BUS_DEVICE *EmuBusDevice; 332 EMU_IO_DEVICE *EmuDevice; 333 EMU_THUNK_PROTOCOL *EmuThunk; 334 335 // 336 // Complete all outstanding transactions to Controller. 337 // Don't allow any new transaction to Controller to be started. 338 // 339 340 if (NumberOfChildren == 0) { 341 // 342 // Close the bus driver 343 // 344 Status = gBS->OpenProtocol ( 345 ControllerHandle, 346 &gEfiCallerIdGuid, 347 (VOID **)&EmuBusDevice, 348 This->DriverBindingHandle, 349 ControllerHandle, 350 EFI_OPEN_PROTOCOL_GET_PROTOCOL 351 ); 352 if (EFI_ERROR (Status)) { 353 return Status; 354 } 355 356 gBS->UninstallMultipleProtocolInterfaces ( 357 ControllerHandle, 358 &gEfiCallerIdGuid, EmuBusDevice, 359 NULL 360 ); 361 362 FreeUnicodeStringTable (EmuBusDevice->ControllerNameTable); 363 364 gBS->FreePool (EmuBusDevice); 365 366 gBS->CloseProtocol ( 367 ControllerHandle, 368 &gEmuThunkProtocolGuid, 369 This->DriverBindingHandle, 370 ControllerHandle 371 ); 372 373 gBS->CloseProtocol ( 374 ControllerHandle, 375 &gEfiDevicePathProtocolGuid, 376 This->DriverBindingHandle, 377 ControllerHandle 378 ); 379 return EFI_SUCCESS; 380 } 381 382 AllChildrenStopped = TRUE; 383 384 for (Index = 0; Index < NumberOfChildren; Index++) { 385 386 Status = gBS->OpenProtocol ( 387 ChildHandleBuffer[Index], 388 &gEmuIoThunkProtocolGuid, 389 (VOID **)&EmuIoThunk, 390 This->DriverBindingHandle, 391 ControllerHandle, 392 EFI_OPEN_PROTOCOL_GET_PROTOCOL 393 ); 394 if (!EFI_ERROR (Status)) { 395 EmuDevice = EMU_IO_DEVICE_FROM_THIS (EmuIoThunk); 396 397 Status = gBS->CloseProtocol ( 398 ControllerHandle, 399 &gEmuThunkProtocolGuid, 400 This->DriverBindingHandle, 401 EmuDevice->Handle 402 ); 403 404 Status = gBS->UninstallMultipleProtocolInterfaces ( 405 EmuDevice->Handle, 406 &gEfiDevicePathProtocolGuid, EmuDevice->DevicePath, 407 &gEmuIoThunkProtocolGuid, &EmuDevice->EmuIoThunk, 408 NULL 409 ); 410 411 if (EFI_ERROR (Status)) { 412 gBS->OpenProtocol ( 413 ControllerHandle, 414 &gEmuThunkProtocolGuid, 415 (VOID **) &EmuThunk , 416 This->DriverBindingHandle, 417 EmuDevice->Handle, 418 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 419 ); 420 } else { 421 // 422 // Close the child handle 423 // 424 FreeUnicodeStringTable (EmuDevice->ControllerNameTable); 425 FreePool (EmuDevice); 426 } 427 } 428 429 if (EFI_ERROR (Status)) { 430 AllChildrenStopped = FALSE; 431 } 432 } 433 434 if (!AllChildrenStopped) { 435 return EFI_DEVICE_ERROR; 436 } 437 438 return EFI_SUCCESS; 439 } 440 441 442 /*++ 443 444 Routine Description: 445 Create a device path node using Guid and InstanceNumber and append it to 446 the passed in RootDevicePath 447 448 Arguments: 449 RootDevicePath - Root of the device path to return. 450 451 Guid - GUID to use in vendor device path node. 452 453 InstanceNumber - Instance number to use in the vendor device path. This 454 argument is needed to make sure each device path is unique. 455 456 Returns: 457 458 EFI_DEVICE_PATH_PROTOCOL 459 460 **/ 461 EFI_DEVICE_PATH_PROTOCOL * 462 EmuBusCreateDevicePath ( 463 IN EFI_DEVICE_PATH_PROTOCOL *RootDevicePath, 464 IN EFI_GUID *Guid, 465 IN UINT16 InstanceNumber 466 ) 467 { 468 EMU_VENDOR_DEVICE_PATH_NODE DevicePath; 469 470 DevicePath.VendorDevicePath.Header.Type = HARDWARE_DEVICE_PATH; 471 DevicePath.VendorDevicePath.Header.SubType = HW_VENDOR_DP; 472 SetDevicePathNodeLength (&DevicePath.VendorDevicePath.Header, sizeof (EMU_VENDOR_DEVICE_PATH_NODE)); 473 474 // 475 // The GUID defines the Class 476 // 477 CopyMem (&DevicePath.VendorDevicePath.Guid, Guid, sizeof (EFI_GUID)); 478 479 // 480 // Add an instance number so we can make sure there are no Device Path 481 // duplication. 482 // 483 DevicePath.Instance = InstanceNumber; 484 485 return AppendDevicePathNode ( 486 RootDevicePath, 487 (EFI_DEVICE_PATH_PROTOCOL *) &DevicePath 488 ); 489 } 490 491 492 493 /** 494 The user Entry Point for module EmuBusDriver. The user code starts with this function. 495 496 @param[in] ImageHandle The firmware allocated handle for the EFI image. 497 @param[in] SystemTable A pointer to the EFI System Table. 498 499 @retval EFI_SUCCESS The entry point is executed successfully. 500 @retval other Some error occurs when executing this entry point. 501 502 **/ 503 EFI_STATUS 504 EFIAPI 505 InitializeEmuBusDriver ( 506 IN EFI_HANDLE ImageHandle, 507 IN EFI_SYSTEM_TABLE *SystemTable 508 ) 509 { 510 EFI_STATUS Status; 511 512 Status = EfiLibInstallAllDriverProtocols ( 513 ImageHandle, 514 SystemTable, 515 &gEmuBusDriverBinding, 516 ImageHandle, 517 &gEmuBusDriverComponentName, 518 NULL, 519 NULL 520 ); 521 ASSERT_EFI_ERROR (Status); 522 523 524 return Status; 525 } 526 527 528 529 530