]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - EmbeddedPkg/Universal/MmcDxe/Mmc.c
Omap35xxPkg/MmcHostDxe: Clean code to respect EDK2 coding convention
[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, 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
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
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
62 InitializeListHead (&mMmcHostPool);\r
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
73 InsertTailList (&mMmcHostPool, &(MmcHostInstance->Link));\r
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
84 RemoveEntryList (&(MmcHostInstance->Link));\r
85}\r
86\r
87MMC_HOST_INSTANCE* CreateMmcHostInstance (\r
88 IN EFI_MMC_HOST_PROTOCOL* MmcHost\r
89 )\r
90{\r
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
95\r
96 MmcHostInstance = AllocateZeroPool (sizeof (MMC_HOST_INSTANCE));\r
97 if (MmcHostInstance == NULL) {\r
98 return NULL;\r
99 }\r
100\r
101 MmcHostInstance->Signature = MMC_HOST_INSTANCE_SIGNATURE;\r
102\r
103 MmcHostInstance->State = MmcHwInitializationState;\r
104\r
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
109\r
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
115\r
116 MmcHostInstance->MmcHost = MmcHost;\r
117\r
118 // Create DevicePath for the new MMC Host\r
119 Status = MmcHost->BuildDevicePath(&NewDevicePathNode);\r
120 if (EFI_ERROR (Status)) {\r
121 goto FREE_MEDIA;\r
122 }\r
123\r
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
135 &gEfiBlockIoProtocolGuid,&MmcHostInstance->BlockIo,\r
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
144\r
145FREE_DEVICE_PATH:\r
146 FreePool(DevicePath);\r
147\r
148FREE_MEDIA:\r
149 FreePool(MmcHostInstance->BlockIo.Media);\r
150\r
151FREE_INSTANCE:\r
152 FreePool(MmcHostInstance);\r
153\r
154 return NULL;\r
155}\r
156\r
157EFI_STATUS DestroyMmcHostInstance (\r
158 IN MMC_HOST_INSTANCE* MmcHostInstance\r
159 )\r
160{\r
161 EFI_STATUS Status;\r
162\r
163 // Uninstall Protocol Interfaces\r
164 Status = gBS->UninstallMultipleProtocolInterfaces (\r
165 MmcHostInstance->MmcHandle,\r
166 &gEfiBlockIoProtocolGuid,&(MmcHostInstance->BlockIo),\r
167 &gEfiDevicePathProtocolGuid,MmcHostInstance->DevicePath,\r
168 NULL\r
169 );\r
170 ASSERT_EFI_ERROR (Status);\r
171\r
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
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
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
201 //\r
202 // Check if RemainingDevicePath is the End of Device Path Node,\r
203 // if yes, go on checking other conditions\r
204 //\r
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
216 }\r
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
231 return EFI_SUCCESS;\r
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
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
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
269 //\r
270 // Check if RemainingDevicePath is the End of Device Path Node,\r
271 // if yes, return EFI_SUCCESS\r
272 //\r
273 if (IsDevicePathEnd (RemainingDevicePath)) {\r
274 return EFI_SUCCESS;\r
275 }\r
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
292 }\r
293 return Status;\r
294 }\r
295\r
296 MmcHostInstance = CreateMmcHostInstance(MmcHost);\r
297 if (MmcHostInstance != NULL) {\r
298 // Add the handle to the pool\r
299 InsertMmcHost (MmcHostInstance);\r
300\r
301 MmcHostInstance->Initialized = FALSE;\r
302\r
303 // Detect card presence now\r
304 CheckCardsCallback (NULL, NULL);\r
305 }\r
306\r
307 return EFI_SUCCESS;\r
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
322 EFI_STATUS Status = EFI_SUCCESS;\r
323 LIST_ENTRY *CurrentLink;\r
324 MMC_HOST_INSTANCE *MmcHostInstance;\r
325\r
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
349}\r
350\r
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
367 if (MmcHostInstance->MmcHost->IsCardPresent() == !MmcHostInstance->Initialized) {\r
368 MmcHostInstance->State = MmcHwInitializationState;\r
369 MmcHostInstance->BlockIo.Media->MediaPresent = !MmcHostInstance->Initialized;\r
370 MmcHostInstance->Initialized = !MmcHostInstance->Initialized;\r
371\r
372 if(MmcHostInstance->BlockIo.Media->MediaPresent) {\r
373 InitializeMmcDevice(MmcHostInstance);\r
374 }\r
375\r
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
392\r
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
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
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
455 return Status;\r
456}\r