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