1 /** @file 2 Main file of the MMC Dxe driver. The driver entrypoint is defined into this file. 3 4 Copyright (c) 2011-2013, ARM Limited. All rights reserved. 5 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 #include <Protocol/DevicePath.h> 17 18 #include <Library/BaseLib.h> 19 #include <Library/BaseMemoryLib.h> 20 #include <Library/MemoryAllocationLib.h> 21 #include <Library/UefiBootServicesTableLib.h> 22 #include <Library/DevicePathLib.h> 23 24 #include "Mmc.h" 25 26 EFI_BLOCK_IO_MEDIA mMmcMediaTemplate = { 27 SIGNATURE_32('m','m','c','o'), // MediaId 28 TRUE, // RemovableMedia 29 FALSE, // MediaPresent 30 FALSE, // LogicalPartition 31 FALSE, // ReadOnly 32 FALSE, // WriteCaching 33 512, // BlockSize 34 4, // IoAlign 35 0, // Pad 36 0 // LastBlock 37 }; 38 39 // 40 // This device structure is serviced as a header. 41 // Its next field points to the first root bridge device node. 42 // 43 LIST_ENTRY mMmcHostPool; 44 45 /** 46 Event triggered by the timer to check if any cards have been removed 47 or if new ones have been plugged in 48 **/ 49 50 EFI_EVENT gCheckCardsEvent; 51 52 /** 53 Initialize the MMC Host Pool to support multiple MMC devices 54 **/ 55 VOID 56 InitializeMmcHostPool ( 57 VOID 58 ) 59 { 60 InitializeListHead (&mMmcHostPool); 61 } 62 63 /** 64 Insert a new Mmc Host controller to the pool 65 **/ 66 VOID 67 InsertMmcHost ( 68 IN MMC_HOST_INSTANCE *MmcHostInstance 69 ) 70 { 71 InsertTailList (&mMmcHostPool, &(MmcHostInstance->Link)); 72 } 73 74 /* 75 Remove a new Mmc Host controller to the pool 76 */ 77 VOID 78 RemoveMmcHost ( 79 IN MMC_HOST_INSTANCE *MmcHostInstance 80 ) 81 { 82 RemoveEntryList (&(MmcHostInstance->Link)); 83 } 84 85 MMC_HOST_INSTANCE* CreateMmcHostInstance ( 86 IN EFI_MMC_HOST_PROTOCOL* MmcHost 87 ) 88 { 89 EFI_STATUS Status; 90 MMC_HOST_INSTANCE* MmcHostInstance; 91 EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode; 92 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 93 94 MmcHostInstance = AllocateZeroPool (sizeof (MMC_HOST_INSTANCE)); 95 if (MmcHostInstance == NULL) { 96 return NULL; 97 } 98 99 MmcHostInstance->Signature = MMC_HOST_INSTANCE_SIGNATURE; 100 101 MmcHostInstance->State = MmcHwInitializationState; 102 103 MmcHostInstance->BlockIo.Media = AllocateCopyPool (sizeof(EFI_BLOCK_IO_MEDIA), &mMmcMediaTemplate); 104 if (MmcHostInstance->BlockIo.Media == NULL) { 105 goto FREE_INSTANCE; 106 } 107 108 MmcHostInstance->BlockIo.Revision = EFI_BLOCK_IO_INTERFACE_REVISION; 109 MmcHostInstance->BlockIo.Reset = MmcReset; 110 MmcHostInstance->BlockIo.ReadBlocks = MmcReadBlocks; 111 MmcHostInstance->BlockIo.WriteBlocks = MmcWriteBlocks; 112 MmcHostInstance->BlockIo.FlushBlocks = MmcFlushBlocks; 113 114 MmcHostInstance->EraseBlockProtocol.Revision = EFI_ERASE_BLOCK_PROTOCOL_REVISION; 115 MmcHostInstance->EraseBlockProtocol.EraseLengthGranularity = 1; //TO BE CHANGED, SHIVA 116 MmcHostInstance->EraseBlockProtocol.EraseBlocks = MmcEraseBlocks; 117 118 MmcHostInstance->MmcHost = MmcHost; 119 120 // Create DevicePath for the new MMC Host 121 Status = MmcHost->BuildDevicePath (MmcHost, &NewDevicePathNode); 122 if (EFI_ERROR (Status)) { 123 goto FREE_MEDIA; 124 } 125 126 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocatePool (END_DEVICE_PATH_LENGTH); 127 if (DevicePath == NULL) { 128 goto FREE_MEDIA; 129 } 130 131 SetDevicePathEndNode (DevicePath); 132 MmcHostInstance->DevicePath = AppendDevicePathNode (DevicePath, NewDevicePathNode); 133 134 // Publish BlockIO protocol interface 135 Status = gBS->InstallMultipleProtocolInterfaces ( 136 &MmcHostInstance->MmcHandle, 137 &gEfiBlockIoProtocolGuid,&MmcHostInstance->BlockIo, 138 &gEfiEraseBlockProtocolGuid,&MmcHostInstance->EraseBlockProtocol, 139 &gEfiDevicePathProtocolGuid,MmcHostInstance->DevicePath, 140 NULL 141 ); 142 if (EFI_ERROR(Status)) { 143 goto FREE_DEVICE_PATH; 144 } 145 146 return MmcHostInstance; 147 148 FREE_DEVICE_PATH: 149 FreePool(DevicePath); 150 151 FREE_MEDIA: 152 FreePool(MmcHostInstance->BlockIo.Media); 153 154 FREE_INSTANCE: 155 FreePool(MmcHostInstance); 156 157 return NULL; 158 } 159 160 EFI_STATUS DestroyMmcHostInstance ( 161 IN MMC_HOST_INSTANCE* MmcHostInstance 162 ) 163 { 164 EFI_STATUS Status; 165 166 // Uninstall Protocol Interfaces 167 Status = gBS->UninstallMultipleProtocolInterfaces ( 168 MmcHostInstance->MmcHandle, 169 &gEfiBlockIoProtocolGuid,&(MmcHostInstance->BlockIo), 170 &gEfiEraseBlockProtocolGuid,&MmcHostInstance->EraseBlockProtocol, 171 &gEfiDevicePathProtocolGuid,MmcHostInstance->DevicePath, 172 NULL 173 ); 174 ASSERT_EFI_ERROR (Status); 175 176 // Free Memory allocated for the instance 177 if (MmcHostInstance->BlockIo.Media) { 178 FreePool(MmcHostInstance->BlockIo.Media); 179 } 180 FreePool (MmcHostInstance); 181 182 return Status; 183 } 184 185 /** 186 This function checks if the controller implement the Mmc Host and the Device Path Protocols 187 **/ 188 EFI_STATUS 189 EFIAPI 190 MmcDriverBindingSupported ( 191 IN EFI_DRIVER_BINDING_PROTOCOL *This, 192 IN EFI_HANDLE Controller, 193 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 194 ) 195 { 196 EFI_STATUS Status; 197 //EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; 198 EFI_MMC_HOST_PROTOCOL *MmcHost; 199 EFI_DEV_PATH_PTR Node; 200 201 // 202 // Check RemainingDevicePath validation 203 // 204 if (RemainingDevicePath != NULL) { 205 // 206 // Check if RemainingDevicePath is the End of Device Path Node, 207 // if yes, go on checking other conditions 208 // 209 if (!IsDevicePathEnd (RemainingDevicePath)) { 210 // 211 // If RemainingDevicePath isn't the End of Device Path Node, 212 // check its validation 213 // 214 Node.DevPath = RemainingDevicePath; 215 if (Node.DevPath->Type != HARDWARE_DEVICE_PATH || 216 Node.DevPath->SubType != HW_VENDOR_DP || 217 DevicePathNodeLength(Node.DevPath) != sizeof(VENDOR_DEVICE_PATH)) { 218 return EFI_UNSUPPORTED; 219 } 220 } 221 } 222 223 // 224 // Check if Mmc Host protocol is installed by platform 225 // 226 Status = gBS->OpenProtocol ( 227 Controller, 228 &gEfiMmcHostProtocolGuid, 229 (VOID **) &MmcHost, 230 This->DriverBindingHandle, 231 Controller, 232 EFI_OPEN_PROTOCOL_BY_DRIVER 233 ); 234 if (Status == EFI_ALREADY_STARTED) { 235 return EFI_SUCCESS; 236 } 237 if (EFI_ERROR (Status)) { 238 return Status; 239 } 240 241 // 242 // Close the Mmc Host used to perform the supported test 243 // 244 gBS->CloseProtocol ( 245 Controller, 246 &gEfiMmcHostProtocolGuid, 247 This->DriverBindingHandle, 248 Controller 249 ); 250 251 return EFI_SUCCESS; 252 } 253 254 /** 255 256 **/ 257 EFI_STATUS 258 EFIAPI 259 MmcDriverBindingStart ( 260 IN EFI_DRIVER_BINDING_PROTOCOL *This, 261 IN EFI_HANDLE Controller, 262 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 263 ) 264 { 265 EFI_STATUS Status; 266 MMC_HOST_INSTANCE *MmcHostInstance; 267 EFI_MMC_HOST_PROTOCOL *MmcHost; 268 269 // 270 // Check RemainingDevicePath validation 271 // 272 if (RemainingDevicePath != NULL) { 273 // 274 // Check if RemainingDevicePath is the End of Device Path Node, 275 // if yes, return EFI_SUCCESS 276 // 277 if (IsDevicePathEnd (RemainingDevicePath)) { 278 return EFI_SUCCESS; 279 } 280 } 281 282 // 283 // Get the Mmc Host protocol 284 // 285 Status = gBS->OpenProtocol ( 286 Controller, 287 &gEfiMmcHostProtocolGuid, 288 (VOID **) &MmcHost, 289 This->DriverBindingHandle, 290 Controller, 291 EFI_OPEN_PROTOCOL_BY_DRIVER 292 ); 293 if (EFI_ERROR (Status)) { 294 if (Status == EFI_ALREADY_STARTED) { 295 return EFI_SUCCESS; 296 } 297 return Status; 298 } 299 300 MmcHostInstance = CreateMmcHostInstance(MmcHost); 301 if (MmcHostInstance != NULL) { 302 // Add the handle to the pool 303 InsertMmcHost (MmcHostInstance); 304 305 MmcHostInstance->Initialized = FALSE; 306 307 // Detect card presence now 308 CheckCardsCallback (NULL, NULL); 309 } 310 311 return EFI_SUCCESS; 312 } 313 314 /** 315 316 **/ 317 EFI_STATUS 318 EFIAPI 319 MmcDriverBindingStop ( 320 IN EFI_DRIVER_BINDING_PROTOCOL *This, 321 IN EFI_HANDLE Controller, 322 IN UINTN NumberOfChildren, 323 IN EFI_HANDLE *ChildHandleBuffer 324 ) 325 { 326 EFI_STATUS Status = EFI_SUCCESS; 327 LIST_ENTRY *CurrentLink; 328 MMC_HOST_INSTANCE *MmcHostInstance; 329 330 MMC_TRACE("MmcDriverBindingStop()"); 331 332 // For each MMC instance 333 CurrentLink = mMmcHostPool.ForwardLink; 334 while (CurrentLink != NULL && CurrentLink != &mMmcHostPool && (Status == EFI_SUCCESS)) { 335 MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK(CurrentLink); 336 ASSERT(MmcHostInstance != NULL); 337 338 // Close gEfiMmcHostProtocolGuid 339 Status = gBS->CloseProtocol ( 340 Controller, 341 &gEfiMmcHostProtocolGuid,(VOID **) &MmcHostInstance->MmcHost, 342 This->DriverBindingHandle 343 ); 344 345 // Remove MMC Host Instance from the pool 346 RemoveMmcHost (MmcHostInstance); 347 348 // Destroy MmcHostInstance 349 DestroyMmcHostInstance (MmcHostInstance); 350 } 351 352 return Status; 353 } 354 355 VOID 356 EFIAPI 357 CheckCardsCallback ( 358 IN EFI_EVENT Event, 359 IN VOID *Context 360 ) 361 { 362 LIST_ENTRY *CurrentLink; 363 MMC_HOST_INSTANCE *MmcHostInstance; 364 EFI_STATUS Status; 365 366 CurrentLink = mMmcHostPool.ForwardLink; 367 while (CurrentLink != NULL && CurrentLink != &mMmcHostPool) { 368 MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK(CurrentLink); 369 ASSERT(MmcHostInstance != NULL); 370 371 if (MmcHostInstance->MmcHost->IsCardPresent (MmcHostInstance->MmcHost) == !MmcHostInstance->Initialized) { 372 MmcHostInstance->State = MmcHwInitializationState; 373 MmcHostInstance->BlockIo.Media->MediaPresent = !MmcHostInstance->Initialized; 374 MmcHostInstance->Initialized = !MmcHostInstance->Initialized; 375 376 if (MmcHostInstance->BlockIo.Media->MediaPresent) { 377 InitializeMmcDevice (MmcHostInstance); 378 } 379 380 Status = gBS->ReinstallProtocolInterface ( 381 (MmcHostInstance->MmcHandle), 382 &gEfiBlockIoProtocolGuid, 383 &(MmcHostInstance->BlockIo), 384 &(MmcHostInstance->BlockIo) 385 ); 386 Status = gBS->ReinstallProtocolInterface ( 387 (MmcHostInstance->MmcHandle), 388 &gEfiEraseBlockProtocolGuid, 389 &(MmcHostInstance->EraseBlockProtocol), 390 &(MmcHostInstance->EraseBlockProtocol) 391 ); 392 393 if (EFI_ERROR(Status)) { 394 Print(L"MMC Card: Error reinstalling BlockIo interface\n"); 395 } 396 } 397 398 CurrentLink = CurrentLink->ForwardLink; 399 } 400 } 401 402 403 EFI_DRIVER_BINDING_PROTOCOL gMmcDriverBinding = { 404 MmcDriverBindingSupported, 405 MmcDriverBindingStart, 406 MmcDriverBindingStop, 407 0xa, 408 NULL, 409 NULL 410 }; 411 412 /** 413 414 **/ 415 EFI_STATUS 416 EFIAPI 417 MmcDxeInitialize ( 418 IN EFI_HANDLE ImageHandle, 419 IN EFI_SYSTEM_TABLE *SystemTable 420 ) 421 { 422 EFI_STATUS Status; 423 424 // 425 // Initializes MMC Host pool 426 // 427 InitializeMmcHostPool (); 428 429 // 430 // Install driver model protocol(s). 431 // 432 Status = EfiLibInstallDriverBindingComponentName2 ( 433 ImageHandle, 434 SystemTable, 435 &gMmcDriverBinding, 436 ImageHandle, 437 &gMmcComponentName, 438 &gMmcComponentName2 439 ); 440 ASSERT_EFI_ERROR (Status); 441 442 // Install driver diagnostics 443 Status = gBS->InstallMultipleProtocolInterfaces ( 444 &ImageHandle, 445 &gEfiDriverDiagnostics2ProtocolGuid,&gMmcDriverDiagnostics2, 446 NULL 447 ); 448 ASSERT_EFI_ERROR (Status); 449 450 // Use a timer to detect if a card has been plugged in or removed 451 Status = gBS->CreateEvent ( 452 EVT_NOTIFY_SIGNAL | EVT_TIMER, 453 TPL_CALLBACK, 454 CheckCardsCallback, 455 NULL, 456 &gCheckCardsEvent); 457 ASSERT_EFI_ERROR (Status); 458 459 Status = gBS->SetTimer( 460 gCheckCardsEvent, 461 TimerPeriodic, 462 (UINT64)(10*1000*200)); // 200 ms 463 ASSERT_EFI_ERROR (Status); 464 465 return Status; 466 } 467