]> git.proxmox.com Git - mirror_edk2.git/blob - EmbeddedPkg/Universal/MmcDxe/Mmc.c
3b9dc187276ce190e8200c751b89aa3893a41871
[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 if (MmcHostInstance->CardInfo.ECSDData) {
175 FreePages (MmcHostInstance->CardInfo.ECSDData, EFI_SIZE_TO_PAGES (sizeof (ECSD)));
176 }
177 FreePool (MmcHostInstance);
178
179 return Status;
180 }
181
182 /**
183 This function checks if the controller implement the Mmc Host and the Device Path Protocols
184 **/
185 EFI_STATUS
186 EFIAPI
187 MmcDriverBindingSupported (
188 IN EFI_DRIVER_BINDING_PROTOCOL *This,
189 IN EFI_HANDLE Controller,
190 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
191 )
192 {
193 EFI_STATUS Status;
194 //EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
195 EFI_MMC_HOST_PROTOCOL *MmcHost;
196 EFI_DEV_PATH_PTR Node;
197
198 //
199 // Check RemainingDevicePath validation
200 //
201 if (RemainingDevicePath != NULL) {
202 //
203 // Check if RemainingDevicePath is the End of Device Path Node,
204 // if yes, go on checking other conditions
205 //
206 if (!IsDevicePathEnd (RemainingDevicePath)) {
207 //
208 // If RemainingDevicePath isn't the End of Device Path Node,
209 // check its validation
210 //
211 Node.DevPath = RemainingDevicePath;
212 if (Node.DevPath->Type != HARDWARE_DEVICE_PATH ||
213 Node.DevPath->SubType != HW_VENDOR_DP ||
214 DevicePathNodeLength(Node.DevPath) != sizeof(VENDOR_DEVICE_PATH)) {
215 return EFI_UNSUPPORTED;
216 }
217 }
218 }
219
220 //
221 // Check if Mmc Host protocol is installed by platform
222 //
223 Status = gBS->OpenProtocol (
224 Controller,
225 &gEfiMmcHostProtocolGuid,
226 (VOID **) &MmcHost,
227 This->DriverBindingHandle,
228 Controller,
229 EFI_OPEN_PROTOCOL_BY_DRIVER
230 );
231 if (Status == EFI_ALREADY_STARTED) {
232 return EFI_SUCCESS;
233 }
234 if (EFI_ERROR (Status)) {
235 return Status;
236 }
237
238 //
239 // Close the Mmc Host used to perform the supported test
240 //
241 gBS->CloseProtocol (
242 Controller,
243 &gEfiMmcHostProtocolGuid,
244 This->DriverBindingHandle,
245 Controller
246 );
247
248 return EFI_SUCCESS;
249 }
250
251 /**
252
253 **/
254 EFI_STATUS
255 EFIAPI
256 MmcDriverBindingStart (
257 IN EFI_DRIVER_BINDING_PROTOCOL *This,
258 IN EFI_HANDLE Controller,
259 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
260 )
261 {
262 EFI_STATUS Status;
263 MMC_HOST_INSTANCE *MmcHostInstance;
264 EFI_MMC_HOST_PROTOCOL *MmcHost;
265
266 //
267 // Check RemainingDevicePath validation
268 //
269 if (RemainingDevicePath != NULL) {
270 //
271 // Check if RemainingDevicePath is the End of Device Path Node,
272 // if yes, return EFI_SUCCESS
273 //
274 if (IsDevicePathEnd (RemainingDevicePath)) {
275 return EFI_SUCCESS;
276 }
277 }
278
279 //
280 // Get the Mmc Host protocol
281 //
282 Status = gBS->OpenProtocol (
283 Controller,
284 &gEfiMmcHostProtocolGuid,
285 (VOID **) &MmcHost,
286 This->DriverBindingHandle,
287 Controller,
288 EFI_OPEN_PROTOCOL_BY_DRIVER
289 );
290 if (EFI_ERROR (Status)) {
291 if (Status == EFI_ALREADY_STARTED) {
292 return EFI_SUCCESS;
293 }
294 return Status;
295 }
296
297 MmcHostInstance = CreateMmcHostInstance(MmcHost);
298 if (MmcHostInstance != NULL) {
299 // Add the handle to the pool
300 InsertMmcHost (MmcHostInstance);
301
302 MmcHostInstance->Initialized = FALSE;
303
304 // Detect card presence now
305 CheckCardsCallback (NULL, NULL);
306 }
307
308 return EFI_SUCCESS;
309 }
310
311 /**
312
313 **/
314 EFI_STATUS
315 EFIAPI
316 MmcDriverBindingStop (
317 IN EFI_DRIVER_BINDING_PROTOCOL *This,
318 IN EFI_HANDLE Controller,
319 IN UINTN NumberOfChildren,
320 IN EFI_HANDLE *ChildHandleBuffer
321 )
322 {
323 EFI_STATUS Status = EFI_SUCCESS;
324 LIST_ENTRY *CurrentLink;
325 MMC_HOST_INSTANCE *MmcHostInstance;
326
327 MMC_TRACE("MmcDriverBindingStop()");
328
329 // For each MMC instance
330 CurrentLink = mMmcHostPool.ForwardLink;
331 while (CurrentLink != NULL && CurrentLink != &mMmcHostPool && (Status == EFI_SUCCESS)) {
332 MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK(CurrentLink);
333 ASSERT(MmcHostInstance != NULL);
334
335 // Close gEfiMmcHostProtocolGuid
336 Status = gBS->CloseProtocol (
337 Controller,
338 &gEfiMmcHostProtocolGuid,(VOID **) &MmcHostInstance->MmcHost,
339 This->DriverBindingHandle
340 );
341
342 // Remove MMC Host Instance from the pool
343 RemoveMmcHost (MmcHostInstance);
344
345 // Destroy MmcHostInstance
346 DestroyMmcHostInstance (MmcHostInstance);
347 }
348
349 return Status;
350 }
351
352 VOID
353 EFIAPI
354 CheckCardsCallback (
355 IN EFI_EVENT Event,
356 IN VOID *Context
357 )
358 {
359 LIST_ENTRY *CurrentLink;
360 MMC_HOST_INSTANCE *MmcHostInstance;
361 EFI_STATUS Status;
362
363 CurrentLink = mMmcHostPool.ForwardLink;
364 while (CurrentLink != NULL && CurrentLink != &mMmcHostPool) {
365 MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK(CurrentLink);
366 ASSERT(MmcHostInstance != NULL);
367
368 if (MmcHostInstance->MmcHost->IsCardPresent (MmcHostInstance->MmcHost) == !MmcHostInstance->Initialized) {
369 MmcHostInstance->State = MmcHwInitializationState;
370 MmcHostInstance->BlockIo.Media->MediaPresent = !MmcHostInstance->Initialized;
371 MmcHostInstance->Initialized = !MmcHostInstance->Initialized;
372
373 if (MmcHostInstance->BlockIo.Media->MediaPresent) {
374 InitializeMmcDevice (MmcHostInstance);
375 }
376
377 Status = gBS->ReinstallProtocolInterface (
378 (MmcHostInstance->MmcHandle),
379 &gEfiBlockIoProtocolGuid,
380 &(MmcHostInstance->BlockIo),
381 &(MmcHostInstance->BlockIo)
382 );
383
384 if (EFI_ERROR(Status)) {
385 Print(L"MMC Card: Error reinstalling BlockIo interface\n");
386 }
387 }
388
389 CurrentLink = CurrentLink->ForwardLink;
390 }
391 }
392
393
394 EFI_DRIVER_BINDING_PROTOCOL gMmcDriverBinding = {
395 MmcDriverBindingSupported,
396 MmcDriverBindingStart,
397 MmcDriverBindingStop,
398 0xa,
399 NULL,
400 NULL
401 };
402
403 /**
404
405 **/
406 EFI_STATUS
407 EFIAPI
408 MmcDxeInitialize (
409 IN EFI_HANDLE ImageHandle,
410 IN EFI_SYSTEM_TABLE *SystemTable
411 )
412 {
413 EFI_STATUS Status;
414
415 //
416 // Initializes MMC Host pool
417 //
418 InitializeMmcHostPool ();
419
420 //
421 // Install driver model protocol(s).
422 //
423 Status = EfiLibInstallDriverBindingComponentName2 (
424 ImageHandle,
425 SystemTable,
426 &gMmcDriverBinding,
427 ImageHandle,
428 &gMmcComponentName,
429 &gMmcComponentName2
430 );
431 ASSERT_EFI_ERROR (Status);
432
433 // Install driver diagnostics
434 Status = gBS->InstallMultipleProtocolInterfaces (
435 &ImageHandle,
436 &gEfiDriverDiagnostics2ProtocolGuid,&gMmcDriverDiagnostics2,
437 NULL
438 );
439 ASSERT_EFI_ERROR (Status);
440
441 // Use a timer to detect if a card has been plugged in or removed
442 Status = gBS->CreateEvent (
443 EVT_NOTIFY_SIGNAL | EVT_TIMER,
444 TPL_CALLBACK,
445 CheckCardsCallback,
446 NULL,
447 &gCheckCardsEvent);
448 ASSERT_EFI_ERROR (Status);
449
450 Status = gBS->SetTimer(
451 gCheckCardsEvent,
452 TimerPeriodic,
453 (UINT64)(10*1000*200)); // 200 ms
454 ASSERT_EFI_ERROR (Status);
455
456 return Status;
457 }