PageRenderTime 27ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/edk2/EmbeddedPkg/Universal/MmcDxe/Mmc.c

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