]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Universal/MmcDxe/Mmc.c
EmbeddedPkg: MmcDxe: move ECSD into CardInfo structure
[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
174 FreePool (MmcHostInstance);\r
175\r
176 return Status;\r
1bfda055 177}\r
178\r
179/**\r
180 This function checks if the controller implement the Mmc Host and the Device Path Protocols\r
181**/\r
182EFI_STATUS\r
183EFIAPI\r
184MmcDriverBindingSupported (\r
185 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
186 IN EFI_HANDLE Controller,\r
187 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
188 )\r
189{\r
e8e95df4 190 EFI_STATUS Status;\r
191 //EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
192 EFI_MMC_HOST_PROTOCOL *MmcHost;\r
193 EFI_DEV_PATH_PTR Node;\r
194\r
195 //\r
196 // Check RemainingDevicePath validation\r
197 //\r
198 if (RemainingDevicePath != NULL) {\r
1bfda055 199 //\r
e8e95df4 200 // Check if RemainingDevicePath is the End of Device Path Node,\r
201 // if yes, go on checking other conditions\r
1bfda055 202 //\r
e8e95df4 203 if (!IsDevicePathEnd (RemainingDevicePath)) {\r
204 //\r
205 // If RemainingDevicePath isn't the End of Device Path Node,\r
206 // check its validation\r
207 //\r
208 Node.DevPath = RemainingDevicePath;\r
209 if (Node.DevPath->Type != HARDWARE_DEVICE_PATH ||\r
210 Node.DevPath->SubType != HW_VENDOR_DP ||\r
211 DevicePathNodeLength(Node.DevPath) != sizeof(VENDOR_DEVICE_PATH)) {\r
212 return EFI_UNSUPPORTED;\r
213 }\r
1bfda055 214 }\r
e8e95df4 215 }\r
216\r
217 //\r
218 // Check if Mmc Host protocol is installed by platform\r
219 //\r
220 Status = gBS->OpenProtocol (\r
221 Controller,\r
222 &gEfiMmcHostProtocolGuid,\r
223 (VOID **) &MmcHost,\r
224 This->DriverBindingHandle,\r
225 Controller,\r
226 EFI_OPEN_PROTOCOL_BY_DRIVER\r
227 );\r
228 if (Status == EFI_ALREADY_STARTED) {\r
1bfda055 229 return EFI_SUCCESS;\r
e8e95df4 230 }\r
231 if (EFI_ERROR (Status)) {\r
232 return Status;\r
233 }\r
234\r
235 //\r
236 // Close the Mmc Host used to perform the supported test\r
237 //\r
238 gBS->CloseProtocol (\r
239 Controller,\r
240 &gEfiMmcHostProtocolGuid,\r
241 This->DriverBindingHandle,\r
242 Controller\r
243 );\r
244\r
245 return EFI_SUCCESS;\r
1bfda055 246}\r
247\r
248/**\r
3402aac7 249\r
1bfda055 250**/\r
251EFI_STATUS\r
252EFIAPI\r
253MmcDriverBindingStart (\r
254 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
255 IN EFI_HANDLE Controller,\r
256 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
257 )\r
258{\r
e8e95df4 259 EFI_STATUS Status;\r
260 MMC_HOST_INSTANCE *MmcHostInstance;\r
261 EFI_MMC_HOST_PROTOCOL *MmcHost;\r
262\r
263 //\r
264 // Check RemainingDevicePath validation\r
265 //\r
266 if (RemainingDevicePath != NULL) {\r
1bfda055 267 //\r
e8e95df4 268 // Check if RemainingDevicePath is the End of Device Path Node,\r
269 // if yes, return EFI_SUCCESS\r
1bfda055 270 //\r
e8e95df4 271 if (IsDevicePathEnd (RemainingDevicePath)) {\r
272 return EFI_SUCCESS;\r
1bfda055 273 }\r
e8e95df4 274 }\r
275\r
276 //\r
277 // Get the Mmc Host protocol\r
278 //\r
279 Status = gBS->OpenProtocol (\r
280 Controller,\r
281 &gEfiMmcHostProtocolGuid,\r
282 (VOID **) &MmcHost,\r
283 This->DriverBindingHandle,\r
284 Controller,\r
285 EFI_OPEN_PROTOCOL_BY_DRIVER\r
286 );\r
287 if (EFI_ERROR (Status)) {\r
288 if (Status == EFI_ALREADY_STARTED) {\r
289 return EFI_SUCCESS;\r
1bfda055 290 }\r
e8e95df4 291 return Status;\r
292 }\r
1bfda055 293\r
e8e95df4 294 MmcHostInstance = CreateMmcHostInstance(MmcHost);\r
295 if (MmcHostInstance != NULL) {\r
296 // Add the handle to the pool\r
297 InsertMmcHost (MmcHostInstance);\r
3de99375 298\r
299 MmcHostInstance->Initialized = FALSE;\r
40842a5e 300\r
301 // Detect card presence now\r
302 CheckCardsCallback (NULL, NULL);\r
e8e95df4 303 }\r
1bfda055 304\r
e8e95df4 305 return EFI_SUCCESS;\r
1bfda055 306}\r
307\r
308/**\r
3402aac7 309\r
1bfda055 310**/\r
311EFI_STATUS\r
312EFIAPI\r
313MmcDriverBindingStop (\r
314 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
315 IN EFI_HANDLE Controller,\r
316 IN UINTN NumberOfChildren,\r
317 IN EFI_HANDLE *ChildHandleBuffer\r
318 )\r
319{\r
e8e95df4 320 EFI_STATUS Status = EFI_SUCCESS;\r
321 LIST_ENTRY *CurrentLink;\r
322 MMC_HOST_INSTANCE *MmcHostInstance;\r
1bfda055 323\r
e8e95df4 324 MMC_TRACE("MmcDriverBindingStop()");\r
325\r
326 // For each MMC instance\r
327 CurrentLink = mMmcHostPool.ForwardLink;\r
328 while (CurrentLink != NULL && CurrentLink != &mMmcHostPool && (Status == EFI_SUCCESS)) {\r
329 MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK(CurrentLink);\r
330 ASSERT(MmcHostInstance != NULL);\r
331\r
332 // Close gEfiMmcHostProtocolGuid\r
333 Status = gBS->CloseProtocol (\r
334 Controller,\r
335 &gEfiMmcHostProtocolGuid,(VOID **) &MmcHostInstance->MmcHost,\r
336 This->DriverBindingHandle\r
337 );\r
338\r
339 // Remove MMC Host Instance from the pool\r
340 RemoveMmcHost (MmcHostInstance);\r
341\r
342 // Destroy MmcHostInstance\r
343 DestroyMmcHostInstance (MmcHostInstance);\r
344 }\r
345\r
346 return Status;\r
1bfda055 347}\r
348\r
3de99375 349VOID\r
350EFIAPI\r
351CheckCardsCallback (\r
352 IN EFI_EVENT Event,\r
353 IN VOID *Context\r
354 )\r
355{\r
356 LIST_ENTRY *CurrentLink;\r
357 MMC_HOST_INSTANCE *MmcHostInstance;\r
358 EFI_STATUS Status;\r
359\r
360 CurrentLink = mMmcHostPool.ForwardLink;\r
361 while (CurrentLink != NULL && CurrentLink != &mMmcHostPool) {\r
362 MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK(CurrentLink);\r
363 ASSERT(MmcHostInstance != NULL);\r
364\r
16d88c2d 365 if (MmcHostInstance->MmcHost->IsCardPresent (MmcHostInstance->MmcHost) == !MmcHostInstance->Initialized) {\r
3de99375 366 MmcHostInstance->State = MmcHwInitializationState;\r
367 MmcHostInstance->BlockIo.Media->MediaPresent = !MmcHostInstance->Initialized;\r
368 MmcHostInstance->Initialized = !MmcHostInstance->Initialized;\r
369\r
16d88c2d 370 if (MmcHostInstance->BlockIo.Media->MediaPresent) {\r
371 InitializeMmcDevice (MmcHostInstance);\r
40842a5e 372 }\r
373\r
3de99375 374 Status = gBS->ReinstallProtocolInterface (\r
375 (MmcHostInstance->MmcHandle),\r
376 &gEfiBlockIoProtocolGuid,\r
377 &(MmcHostInstance->BlockIo),\r
378 &(MmcHostInstance->BlockIo)\r
379 );\r
380\r
381 if (EFI_ERROR(Status)) {\r
382 Print(L"MMC Card: Error reinstalling BlockIo interface\n");\r
383 }\r
384 }\r
385\r
386 CurrentLink = CurrentLink->ForwardLink;\r
387 }\r
388}\r
389\r
40842a5e 390\r
1bfda055 391EFI_DRIVER_BINDING_PROTOCOL gMmcDriverBinding = {\r
392 MmcDriverBindingSupported,\r
393 MmcDriverBindingStart,\r
394 MmcDriverBindingStop,\r
395 0xa,\r
396 NULL,\r
397 NULL\r
398};\r
399\r
400/**\r
3402aac7 401\r
1bfda055 402**/\r
403EFI_STATUS\r
404EFIAPI\r
405MmcDxeInitialize (\r
406 IN EFI_HANDLE ImageHandle,\r
407 IN EFI_SYSTEM_TABLE *SystemTable\r
408 )\r
409{\r
e8e95df4 410 EFI_STATUS Status;\r
411\r
412 //\r
413 // Initializes MMC Host pool\r
414 //\r
415 InitializeMmcHostPool ();\r
416\r
417 //\r
418 // Install driver model protocol(s).\r
419 //\r
420 Status = EfiLibInstallDriverBindingComponentName2 (\r
421 ImageHandle,\r
422 SystemTable,\r
423 &gMmcDriverBinding,\r
424 ImageHandle,\r
425 &gMmcComponentName,\r
426 &gMmcComponentName2\r
427 );\r
428 ASSERT_EFI_ERROR (Status);\r
429\r
430 // Install driver diagnostics\r
431 Status = gBS->InstallMultipleProtocolInterfaces (\r
432 &ImageHandle,\r
433 &gEfiDriverDiagnostics2ProtocolGuid,&gMmcDriverDiagnostics2,\r
434 NULL\r
435 );\r
436 ASSERT_EFI_ERROR (Status);\r
437\r
3de99375 438 // Use a timer to detect if a card has been plugged in or removed\r
439 Status = gBS->CreateEvent (\r
440 EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
441 TPL_CALLBACK,\r
442 CheckCardsCallback,\r
443 NULL,\r
444 &gCheckCardsEvent);\r
3402aac7
RC
445 ASSERT_EFI_ERROR (Status);\r
446\r
3de99375 447 Status = gBS->SetTimer(\r
448 gCheckCardsEvent,\r
449 TimerPeriodic,\r
450 (UINT64)(10*1000*200)); // 200 ms\r
451 ASSERT_EFI_ERROR (Status);\r
452\r
e8e95df4 453 return Status;\r
1bfda055 454}\r