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