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