Home | History | Annotate | Download | only in MmcDxe
      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