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