]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - EmbeddedPkg/Universal/MmcDxe/Mmc.c
EmbeddedPkg/MmcDxe: Moved all the 'Print*()' functions to MmcDebug.c
[mirror_edk2.git] / EmbeddedPkg / Universal / MmcDxe / Mmc.c
... / ...
CommitLineData
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-2013, 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\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
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
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
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
60 InitializeListHead (&mMmcHostPool);\r
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
71 InsertTailList (&mMmcHostPool, &(MmcHostInstance->Link));\r
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
82 RemoveEntryList (&(MmcHostInstance->Link));\r
83}\r
84\r
85MMC_HOST_INSTANCE* CreateMmcHostInstance (\r
86 IN EFI_MMC_HOST_PROTOCOL* MmcHost\r
87 )\r
88{\r
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
93\r
94 MmcHostInstance = AllocateZeroPool (sizeof (MMC_HOST_INSTANCE));\r
95 if (MmcHostInstance == NULL) {\r
96 return NULL;\r
97 }\r
98\r
99 MmcHostInstance->Signature = MMC_HOST_INSTANCE_SIGNATURE;\r
100\r
101 MmcHostInstance->State = MmcHwInitializationState;\r
102\r
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
107\r
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
113\r
114 MmcHostInstance->MmcHost = MmcHost;\r
115\r
116 // Create DevicePath for the new MMC Host\r
117 Status = MmcHost->BuildDevicePath (MmcHost, &NewDevicePathNode);\r
118 if (EFI_ERROR (Status)) {\r
119 goto FREE_MEDIA;\r
120 }\r
121\r
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
133 &gEfiBlockIoProtocolGuid,&MmcHostInstance->BlockIo,\r
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
142\r
143FREE_DEVICE_PATH:\r
144 FreePool(DevicePath);\r
145\r
146FREE_MEDIA:\r
147 FreePool(MmcHostInstance->BlockIo.Media);\r
148\r
149FREE_INSTANCE:\r
150 FreePool(MmcHostInstance);\r
151\r
152 return NULL;\r
153}\r
154\r
155EFI_STATUS DestroyMmcHostInstance (\r
156 IN MMC_HOST_INSTANCE* MmcHostInstance\r
157 )\r
158{\r
159 EFI_STATUS Status;\r
160\r
161 // Uninstall Protocol Interfaces\r
162 Status = gBS->UninstallMultipleProtocolInterfaces (\r
163 MmcHostInstance->MmcHandle,\r
164 &gEfiBlockIoProtocolGuid,&(MmcHostInstance->BlockIo),\r
165 &gEfiDevicePathProtocolGuid,MmcHostInstance->DevicePath,\r
166 NULL\r
167 );\r
168 ASSERT_EFI_ERROR (Status);\r
169\r
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
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
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
199 //\r
200 // Check if RemainingDevicePath is the End of Device Path Node,\r
201 // if yes, go on checking other conditions\r
202 //\r
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
214 }\r
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
229 return EFI_SUCCESS;\r
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
246}\r
247\r
248/**\r
249 \r
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
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
267 //\r
268 // Check if RemainingDevicePath is the End of Device Path Node,\r
269 // if yes, return EFI_SUCCESS\r
270 //\r
271 if (IsDevicePathEnd (RemainingDevicePath)) {\r
272 return EFI_SUCCESS;\r
273 }\r
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
290 }\r
291 return Status;\r
292 }\r
293\r
294 MmcHostInstance = CreateMmcHostInstance(MmcHost);\r
295 if (MmcHostInstance != NULL) {\r
296 // Add the handle to the pool\r
297 InsertMmcHost (MmcHostInstance);\r
298\r
299 MmcHostInstance->Initialized = FALSE;\r
300\r
301 // Detect card presence now\r
302 CheckCardsCallback (NULL, NULL);\r
303 }\r
304\r
305 return EFI_SUCCESS;\r
306}\r
307\r
308/**\r
309 \r
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
320 EFI_STATUS Status = EFI_SUCCESS;\r
321 LIST_ENTRY *CurrentLink;\r
322 MMC_HOST_INSTANCE *MmcHostInstance;\r
323\r
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
347}\r
348\r
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
365 if (MmcHostInstance->MmcHost->IsCardPresent (MmcHostInstance->MmcHost) == !MmcHostInstance->Initialized) {\r
366 MmcHostInstance->State = MmcHwInitializationState;\r
367 MmcHostInstance->BlockIo.Media->MediaPresent = !MmcHostInstance->Initialized;\r
368 MmcHostInstance->Initialized = !MmcHostInstance->Initialized;\r
369\r
370 if (MmcHostInstance->BlockIo.Media->MediaPresent) {\r
371 InitializeMmcDevice (MmcHostInstance);\r
372 }\r
373\r
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
390\r
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
401 \r
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
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
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
445 ASSERT_EFI_ERROR (Status); \r
446 \r
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
453 return Status;\r
454}\r