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
InitializeMmcHostPool(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
InsertMmcHost(IN MMC_HOST_INSTANCE * MmcHostInstance)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
RemoveMmcHost(IN MMC_HOST_INSTANCE * MmcHostInstance)78 RemoveMmcHost (
79   IN MMC_HOST_INSTANCE      *MmcHostInstance
80   )
81 {
82   RemoveEntryList (&(MmcHostInstance->Link));
83 }
84 
CreateMmcHostInstance(IN EFI_MMC_HOST_PROTOCOL * MmcHost)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 
DestroyMmcHostInstance(IN MMC_HOST_INSTANCE * MmcHostInstance)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
MmcDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)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
MmcDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)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
MmcDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)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
CheckCardsCallback(IN EFI_EVENT Event,IN VOID * Context)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
MmcDxeInitialize(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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