]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Universal/MmcDxe/Mmc.c
EmbeddedPkg/MmcDxe: Create a periodic function to check if a card is present
[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
119 Status = MmcHost->BuildDevicePath(&NewDevicePathNode);\r
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
e8e95df4 302 }\r
1bfda055 303\r
e8e95df4 304 return EFI_SUCCESS;\r
1bfda055 305}\r
306\r
307/**\r
308 \r
309**/\r
310EFI_STATUS\r
311EFIAPI\r
312MmcDriverBindingStop (\r
313 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
314 IN EFI_HANDLE Controller,\r
315 IN UINTN NumberOfChildren,\r
316 IN EFI_HANDLE *ChildHandleBuffer\r
317 )\r
318{\r
e8e95df4 319 EFI_STATUS Status = EFI_SUCCESS;\r
320 LIST_ENTRY *CurrentLink;\r
321 MMC_HOST_INSTANCE *MmcHostInstance;\r
1bfda055 322\r
e8e95df4 323 MMC_TRACE("MmcDriverBindingStop()");\r
324\r
325 // For each MMC instance\r
326 CurrentLink = mMmcHostPool.ForwardLink;\r
327 while (CurrentLink != NULL && CurrentLink != &mMmcHostPool && (Status == EFI_SUCCESS)) {\r
328 MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK(CurrentLink);\r
329 ASSERT(MmcHostInstance != NULL);\r
330\r
331 // Close gEfiMmcHostProtocolGuid\r
332 Status = gBS->CloseProtocol (\r
333 Controller,\r
334 &gEfiMmcHostProtocolGuid,(VOID **) &MmcHostInstance->MmcHost,\r
335 This->DriverBindingHandle\r
336 );\r
337\r
338 // Remove MMC Host Instance from the pool\r
339 RemoveMmcHost (MmcHostInstance);\r
340\r
341 // Destroy MmcHostInstance\r
342 DestroyMmcHostInstance (MmcHostInstance);\r
343 }\r
344\r
345 return Status;\r
1bfda055 346}\r
347\r
3de99375 348VOID\r
349EFIAPI\r
350CheckCardsCallback (\r
351 IN EFI_EVENT Event,\r
352 IN VOID *Context\r
353 )\r
354{\r
355 LIST_ENTRY *CurrentLink;\r
356 MMC_HOST_INSTANCE *MmcHostInstance;\r
357 EFI_STATUS Status;\r
358\r
359 CurrentLink = mMmcHostPool.ForwardLink;\r
360 while (CurrentLink != NULL && CurrentLink != &mMmcHostPool) {\r
361 MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK(CurrentLink);\r
362 ASSERT(MmcHostInstance != NULL);\r
363\r
364 if (MmcHostInstance->MmcHost->IsCardPresent() == !MmcHostInstance->Initialized) {\r
365 MmcHostInstance->State = MmcHwInitializationState;\r
366 MmcHostInstance->BlockIo.Media->MediaPresent = !MmcHostInstance->Initialized;\r
367 MmcHostInstance->Initialized = !MmcHostInstance->Initialized;\r
368\r
369 Status = gBS->ReinstallProtocolInterface (\r
370 (MmcHostInstance->MmcHandle),\r
371 &gEfiBlockIoProtocolGuid,\r
372 &(MmcHostInstance->BlockIo),\r
373 &(MmcHostInstance->BlockIo)\r
374 );\r
375\r
376 if (EFI_ERROR(Status)) {\r
377 Print(L"MMC Card: Error reinstalling BlockIo interface\n");\r
378 }\r
379 }\r
380\r
381 CurrentLink = CurrentLink->ForwardLink;\r
382 }\r
383}\r
384\r
1bfda055 385EFI_DRIVER_BINDING_PROTOCOL gMmcDriverBinding = {\r
386 MmcDriverBindingSupported,\r
387 MmcDriverBindingStart,\r
388 MmcDriverBindingStop,\r
389 0xa,\r
390 NULL,\r
391 NULL\r
392};\r
393\r
394/**\r
395 \r
396**/\r
397EFI_STATUS\r
398EFIAPI\r
399MmcDxeInitialize (\r
400 IN EFI_HANDLE ImageHandle,\r
401 IN EFI_SYSTEM_TABLE *SystemTable\r
402 )\r
403{\r
e8e95df4 404 EFI_STATUS Status;\r
405\r
406 //\r
407 // Initializes MMC Host pool\r
408 //\r
409 InitializeMmcHostPool ();\r
410\r
411 //\r
412 // Install driver model protocol(s).\r
413 //\r
414 Status = EfiLibInstallDriverBindingComponentName2 (\r
415 ImageHandle,\r
416 SystemTable,\r
417 &gMmcDriverBinding,\r
418 ImageHandle,\r
419 &gMmcComponentName,\r
420 &gMmcComponentName2\r
421 );\r
422 ASSERT_EFI_ERROR (Status);\r
423\r
424 // Install driver diagnostics\r
425 Status = gBS->InstallMultipleProtocolInterfaces (\r
426 &ImageHandle,\r
427 &gEfiDriverDiagnostics2ProtocolGuid,&gMmcDriverDiagnostics2,\r
428 NULL\r
429 );\r
430 ASSERT_EFI_ERROR (Status);\r
431\r
3de99375 432 // Use a timer to detect if a card has been plugged in or removed\r
433 Status = gBS->CreateEvent (\r
434 EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
435 TPL_CALLBACK,\r
436 CheckCardsCallback,\r
437 NULL,\r
438 &gCheckCardsEvent);\r
439 ASSERT_EFI_ERROR (Status); \r
440 \r
441 Status = gBS->SetTimer(\r
442 gCheckCardsEvent,\r
443 TimerPeriodic,\r
444 (UINT64)(10*1000*200)); // 200 ms\r
445 ASSERT_EFI_ERROR (Status);\r
446\r
e8e95df4 447 return Status;\r
1bfda055 448}\r