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