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