]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Bus / Sd / EmmcDxe / EmmcDxe.c
CommitLineData
48555339
FT
1/** @file\r
2 The EmmcDxe driver is used to manage the EMMC device.\r
3\r
4 It produces BlockIo, BlockIo2 and StorageSecurity protocols to allow upper layer\r
5 access the EMMC device.\r
6\r
d1102dba 7 Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 8 SPDX-License-Identifier: BSD-2-Clause-Patent\r
48555339
FT
9\r
10**/\r
11\r
12#include "EmmcDxe.h"\r
13\r
14//\r
15// EmmcDxe Driver Binding Protocol Instance\r
16//\r
17EFI_DRIVER_BINDING_PROTOCOL gEmmcDxeDriverBinding = {\r
18 EmmcDxeDriverBindingSupported,\r
19 EmmcDxeDriverBindingStart,\r
20 EmmcDxeDriverBindingStop,\r
21 0x10,\r
22 NULL,\r
23 NULL\r
24};\r
25\r
26//\r
27// Template for Emmc Partitions.\r
28//\r
29EMMC_PARTITION mEmmcPartitionTemplate = {\r
30 EMMC_PARTITION_SIGNATURE, // Signature\r
31 FALSE, // Enable\r
32 EmmcPartitionUnknown, // PartitionType\r
33 NULL, // Handle\r
34 NULL, // DevicePath\r
35 { // BlockIo\r
36 EFI_BLOCK_IO_PROTOCOL_REVISION,\r
37 NULL,\r
38 EmmcReset,\r
39 EmmcReadBlocks,\r
40 EmmcWriteBlocks,\r
41 EmmcFlushBlocks\r
42 },\r
43 { // BlockIo2\r
44 NULL,\r
45 EmmcResetEx,\r
46 EmmcReadBlocksEx,\r
47 EmmcWriteBlocksEx,\r
48 EmmcFlushBlocksEx\r
49 },\r
50 { // BlockMedia\r
51 0, // MediaId\r
52 FALSE, // RemovableMedia\r
53 TRUE, // MediaPresent\r
54 FALSE, // LogicPartition\r
55 FALSE, // ReadOnly\r
56 FALSE, // WritingCache\r
57 0x200, // BlockSize\r
58 0, // IoAlign\r
59 0 // LastBlock\r
60 },\r
61 { // StorageSecurity\r
62 EmmcSecurityProtocolIn,\r
63 EmmcSecurityProtocolOut\r
64 },\r
275d5136
FT
65 { // EraseBlock\r
66 EFI_ERASE_BLOCK_PROTOCOL_REVISION,\r
67 1,\r
68 EmmcEraseBlocks\r
69 },\r
19b2cb5c
HW
70 { // DiskInfo\r
71 EFI_DISK_INFO_SD_MMC_INTERFACE_GUID,\r
72 EmmcDiskInfoInquiry,\r
73 EmmcDiskInfoIdentify,\r
74 EmmcDiskInfoSenseData,\r
75 EmmcDiskInfoWhichIde\r
76 },\r
48555339
FT
77 {\r
78 NULL,\r
79 NULL\r
80 },\r
81 NULL // Device\r
82};\r
83\r
84/**\r
85 Decode and print EMMC CSD Register content.\r
86\r
87 @param[in] Csd Pointer to EMMC_CSD data structure.\r
88\r
89 @retval EFI_SUCCESS The function completed successfully\r
90**/\r
91EFI_STATUS\r
92DumpCsd (\r
93 IN EMMC_CSD *Csd\r
94 )\r
95{\r
96 DEBUG((DEBUG_INFO, "== Dump Emmc Csd Register==\n"));\r
97 DEBUG((DEBUG_INFO, " CSD structure 0x%x\n", Csd->CsdStructure));\r
98 DEBUG((DEBUG_INFO, " System specification version 0x%x\n", Csd->SpecVers));\r
99 DEBUG((DEBUG_INFO, " Data read access-time 1 0x%x\n", Csd->Taac));\r
100 DEBUG((DEBUG_INFO, " Data read access-time 2 0x%x\n", Csd->Nsac));\r
101 DEBUG((DEBUG_INFO, " Max. bus clock frequency 0x%x\n", Csd->TranSpeed));\r
102 DEBUG((DEBUG_INFO, " Device command classes 0x%x\n", Csd->Ccc));\r
103 DEBUG((DEBUG_INFO, " Max. read data block length 0x%x\n", Csd->ReadBlLen));\r
104 DEBUG((DEBUG_INFO, " Partial blocks for read allowed 0x%x\n", Csd->ReadBlPartial));\r
105 DEBUG((DEBUG_INFO, " Write block misalignment 0x%x\n", Csd->WriteBlkMisalign));\r
106 DEBUG((DEBUG_INFO, " Read block misalignment 0x%x\n", Csd->ReadBlkMisalign));\r
107 DEBUG((DEBUG_INFO, " DSR implemented 0x%x\n", Csd->DsrImp));\r
108 DEBUG((DEBUG_INFO, " Device size 0x%x\n", Csd->CSizeLow | (Csd->CSizeHigh << 2)));\r
109 DEBUG((DEBUG_INFO, " Max. read current @ VDD min 0x%x\n", Csd->VddRCurrMin));\r
110 DEBUG((DEBUG_INFO, " Max. read current @ VDD max 0x%x\n", Csd->VddRCurrMax));\r
111 DEBUG((DEBUG_INFO, " Max. write current @ VDD min 0x%x\n", Csd->VddWCurrMin));\r
112 DEBUG((DEBUG_INFO, " Max. write current @ VDD max 0x%x\n", Csd->VddWCurrMax));\r
113 DEBUG((DEBUG_INFO, " Device size multiplier 0x%x\n", Csd->CSizeMult));\r
114 DEBUG((DEBUG_INFO, " Erase group size 0x%x\n", Csd->EraseGrpSize));\r
115 DEBUG((DEBUG_INFO, " Erase group size multiplier 0x%x\n", Csd->EraseGrpMult));\r
116 DEBUG((DEBUG_INFO, " Write protect group size 0x%x\n", Csd->WpGrpSize));\r
117 DEBUG((DEBUG_INFO, " Write protect group enable 0x%x\n", Csd->WpGrpEnable));\r
118 DEBUG((DEBUG_INFO, " Manufacturer default ECC 0x%x\n", Csd->DefaultEcc));\r
119 DEBUG((DEBUG_INFO, " Write speed factor 0x%x\n", Csd->R2WFactor));\r
120 DEBUG((DEBUG_INFO, " Max. write data block length 0x%x\n", Csd->WriteBlLen));\r
121 DEBUG((DEBUG_INFO, " Partial blocks for write allowed 0x%x\n", Csd->WriteBlPartial));\r
122 DEBUG((DEBUG_INFO, " Content protection application 0x%x\n", Csd->ContentProtApp));\r
123 DEBUG((DEBUG_INFO, " File format group 0x%x\n", Csd->FileFormatGrp));\r
124 DEBUG((DEBUG_INFO, " Copy flag (OTP) 0x%x\n", Csd->Copy));\r
125 DEBUG((DEBUG_INFO, " Permanent write protection 0x%x\n", Csd->PermWriteProtect));\r
126 DEBUG((DEBUG_INFO, " Temporary write protection 0x%x\n", Csd->TmpWriteProtect));\r
127 DEBUG((DEBUG_INFO, " File format 0x%x\n", Csd->FileFormat));\r
128 DEBUG((DEBUG_INFO, " ECC code 0x%x\n", Csd->Ecc));\r
129\r
130 return EFI_SUCCESS;\r
131}\r
132\r
133/**\r
134 Decode and print EMMC EXT_CSD Register content.\r
135\r
136 @param[in] ExtCsd Pointer to the EMMC_EXT_CSD data structure.\r
137\r
138 @retval EFI_SUCCESS The function completed successfully\r
139**/\r
140EFI_STATUS\r
141DumpExtCsd (\r
142 IN EMMC_EXT_CSD *ExtCsd\r
143 )\r
144{\r
145 DEBUG((DEBUG_INFO, "==Dump Emmc ExtCsd Register==\n"));\r
146 DEBUG((DEBUG_INFO, " Supported Command Sets 0x%x\n", ExtCsd->CmdSet));\r
147 DEBUG((DEBUG_INFO, " HPI features 0x%x\n", ExtCsd->HpiFeatures));\r
148 DEBUG((DEBUG_INFO, " Background operations support 0x%x\n", ExtCsd->BkOpsSupport));\r
149 DEBUG((DEBUG_INFO, " Background operations status 0x%x\n", ExtCsd->BkopsStatus));\r
150 DEBUG((DEBUG_INFO, " Number of correctly programmed sectors 0x%x\n", *((UINT32*)&ExtCsd->CorrectlyPrgSectorsNum[0])));\r
151 DEBUG((DEBUG_INFO, " Initialization time after partitioning 0x%x\n", ExtCsd->IniTimeoutAp));\r
152 DEBUG((DEBUG_INFO, " TRIM Multiplier 0x%x\n", ExtCsd->TrimMult));\r
153 DEBUG((DEBUG_INFO, " Secure Feature support 0x%x\n", ExtCsd->SecFeatureSupport));\r
154 DEBUG((DEBUG_INFO, " Secure Erase Multiplier 0x%x\n", ExtCsd->SecEraseMult));\r
155 DEBUG((DEBUG_INFO, " Secure TRIM Multiplier 0x%x\n", ExtCsd->SecTrimMult));\r
156 DEBUG((DEBUG_INFO, " Boot information 0x%x\n", ExtCsd->BootInfo));\r
157 DEBUG((DEBUG_INFO, " Boot partition size 0x%x\n", ExtCsd->BootSizeMult));\r
158 DEBUG((DEBUG_INFO, " Access size 0x%x\n", ExtCsd->AccSize));\r
159 DEBUG((DEBUG_INFO, " High-capacity erase unit size 0x%x\n", ExtCsd->HcEraseGrpSize));\r
160 DEBUG((DEBUG_INFO, " High-capacity erase timeout 0x%x\n", ExtCsd->EraseTimeoutMult));\r
161 DEBUG((DEBUG_INFO, " Reliable write sector count 0x%x\n", ExtCsd->RelWrSecC));\r
162 DEBUG((DEBUG_INFO, " High-capacity write protect group size 0x%x\n", ExtCsd->HcWpGrpSize));\r
163 DEBUG((DEBUG_INFO, " Sleep/awake timeout 0x%x\n", ExtCsd->SATimeout));\r
164 DEBUG((DEBUG_INFO, " Sector Count 0x%x\n", *((UINT32*)&ExtCsd->SecCount[0])));\r
165 DEBUG((DEBUG_INFO, " Partition switching timing 0x%x\n", ExtCsd->PartitionSwitchTime));\r
166 DEBUG((DEBUG_INFO, " Out-of-interrupt busy timing 0x%x\n", ExtCsd->OutOfInterruptTime));\r
167 DEBUG((DEBUG_INFO, " I/O Driver Strength 0x%x\n", ExtCsd->DriverStrength));\r
168 DEBUG((DEBUG_INFO, " Device type 0x%x\n", ExtCsd->DeviceType));\r
169 DEBUG((DEBUG_INFO, " CSD STRUCTURE 0x%x\n", ExtCsd->CsdStructure));\r
170 DEBUG((DEBUG_INFO, " Extended CSD revision 0x%x\n", ExtCsd->ExtCsdRev));\r
171 DEBUG((DEBUG_INFO, " Command set 0x%x\n", ExtCsd->CmdSet));\r
172 DEBUG((DEBUG_INFO, " Command set revision 0x%x\n", ExtCsd->CmdSetRev));\r
173 DEBUG((DEBUG_INFO, " Power class 0x%x\n", ExtCsd->PowerClass));\r
174 DEBUG((DEBUG_INFO, " High-speed interface timing 0x%x\n", ExtCsd->HsTiming));\r
175 DEBUG((DEBUG_INFO, " Bus width mode 0x%x\n", ExtCsd->BusWidth));\r
176 DEBUG((DEBUG_INFO, " Erased memory content 0x%x\n", ExtCsd->ErasedMemCont));\r
177 DEBUG((DEBUG_INFO, " Partition configuration 0x%x\n", ExtCsd->PartitionConfig));\r
178 DEBUG((DEBUG_INFO, " Boot config protection 0x%x\n", ExtCsd->BootConfigProt));\r
179 DEBUG((DEBUG_INFO, " Boot bus Conditions 0x%x\n", ExtCsd->BootBusConditions));\r
180 DEBUG((DEBUG_INFO, " High-density erase group definition 0x%x\n", ExtCsd->EraseGroupDef));\r
181 DEBUG((DEBUG_INFO, " Boot write protection status register 0x%x\n", ExtCsd->BootWpStatus));\r
182 DEBUG((DEBUG_INFO, " Boot area write protection register 0x%x\n", ExtCsd->BootWp));\r
183 DEBUG((DEBUG_INFO, " User area write protection register 0x%x\n", ExtCsd->UserWp));\r
184 DEBUG((DEBUG_INFO, " FW configuration 0x%x\n", ExtCsd->FwConfig));\r
185 DEBUG((DEBUG_INFO, " RPMB Size 0x%x\n", ExtCsd->RpmbSizeMult));\r
186 DEBUG((DEBUG_INFO, " H/W reset function 0x%x\n", ExtCsd->RstFunction));\r
187 DEBUG((DEBUG_INFO, " Partitioning Support 0x%x\n", ExtCsd->PartitioningSupport));\r
188 DEBUG((DEBUG_INFO, " Max Enhanced Area Size 0x%02x%02x%02x\n", \\r
189 ExtCsd->MaxEnhSizeMult[2], ExtCsd->MaxEnhSizeMult[1], ExtCsd->MaxEnhSizeMult[0]));\r
190 DEBUG((DEBUG_INFO, " Partitions attribute 0x%x\n", ExtCsd->PartitionsAttribute));\r
191 DEBUG((DEBUG_INFO, " Partitioning Setting 0x%x\n", ExtCsd->PartitionSettingCompleted));\r
192 DEBUG((DEBUG_INFO, " General Purpose Partition 1 Size 0x%02x%02x%02x\n", \\r
193 ExtCsd->GpSizeMult[2], ExtCsd->GpSizeMult[1], ExtCsd->GpSizeMult[0]));\r
194 DEBUG((DEBUG_INFO, " General Purpose Partition 2 Size 0x%02x%02x%02x\n", \\r
195 ExtCsd->GpSizeMult[5], ExtCsd->GpSizeMult[4], ExtCsd->GpSizeMult[3]));\r
196 DEBUG((DEBUG_INFO, " General Purpose Partition 3 Size 0x%02x%02x%02x\n", \\r
197 ExtCsd->GpSizeMult[8], ExtCsd->GpSizeMult[7], ExtCsd->GpSizeMult[6]));\r
198 DEBUG((DEBUG_INFO, " General Purpose Partition 4 Size 0x%02x%02x%02x\n", \\r
199 ExtCsd->GpSizeMult[11], ExtCsd->GpSizeMult[10], ExtCsd->GpSizeMult[9]));\r
200 DEBUG((DEBUG_INFO, " Enhanced User Data Area Size 0x%02x%02x%02x\n", \\r
201 ExtCsd->EnhSizeMult[2], ExtCsd->EnhSizeMult[1], ExtCsd->EnhSizeMult[0]));\r
202 DEBUG((DEBUG_INFO, " Enhanced User Data Start Address 0x%x\n", *((UINT32*)&ExtCsd->EnhStartAddr[0])));\r
203 DEBUG((DEBUG_INFO, " Bad Block Management mode 0x%x\n", ExtCsd->SecBadBlkMgmnt));\r
204 DEBUG((DEBUG_INFO, " Native sector size 0x%x\n", ExtCsd->NativeSectorSize));\r
205 DEBUG((DEBUG_INFO, " Sector size emulation 0x%x\n", ExtCsd->UseNativeSector));\r
206 DEBUG((DEBUG_INFO, " Sector size 0x%x\n", ExtCsd->DataSectorSize));\r
207\r
208 return EFI_SUCCESS;\r
209}\r
210\r
211/**\r
212 Get EMMC device model name.\r
213\r
214 @param[in, out] Device The pointer to the EMMC_DEVICE data structure.\r
215 @param[in] Cid Pointer to EMMC_CID data structure.\r
216\r
217 @retval EFI_SUCCESS The function completed successfully\r
218\r
219**/\r
220EFI_STATUS\r
221GetEmmcModelName (\r
222 IN OUT EMMC_DEVICE *Device,\r
223 IN EMMC_CID *Cid\r
224 )\r
225{\r
226 CHAR8 String[EMMC_MODEL_NAME_MAX_LEN];\r
227\r
228 ZeroMem (String, sizeof (String));\r
229 CopyMem (String, &Cid->OemId, sizeof (Cid->OemId));\r
230 String[sizeof (Cid->OemId)] = ' ';\r
231 CopyMem (String + sizeof (Cid->OemId) + 1, Cid->ProductName, sizeof (Cid->ProductName));\r
232 String[sizeof (Cid->OemId) + sizeof (Cid->ProductName)] = ' ';\r
233 CopyMem (String + sizeof (Cid->OemId) + sizeof (Cid->ProductName) + 1, Cid->ProductSerialNumber, sizeof (Cid->ProductSerialNumber));\r
234\r
b68ccac1 235 AsciiStrToUnicodeStrS (String, Device->ModelName, sizeof (Device->ModelName) / sizeof (Device->ModelName[0]));\r
48555339
FT
236\r
237 return EFI_SUCCESS;\r
238}\r
239\r
240/**\r
241 Discover all partitions in the EMMC device.\r
242\r
243 @param[in] Device The pointer to the EMMC_DEVICE data structure.\r
244\r
245 @retval EFI_SUCCESS All the partitions in the device are successfully enumerated.\r
246 @return Others Some error occurs when enumerating the partitions.\r
247\r
248**/\r
249EFI_STATUS\r
250DiscoverAllPartitions (\r
251 IN EMMC_DEVICE *Device\r
252 )\r
253{\r
254 EFI_STATUS Status;\r
48555339
FT
255 EMMC_PARTITION *Partition;\r
256 EMMC_CSD *Csd;\r
257 EMMC_CID *Cid;\r
258 EMMC_EXT_CSD *ExtCsd;\r
259 UINT8 Slot;\r
260 UINT64 Capacity;\r
261 UINT32 DevStatus;\r
262 UINT8 Index;\r
263 UINT32 SecCount;\r
264 UINT32 GpSizeMult;\r
265\r
48555339
FT
266 Slot = Device->Slot;\r
267\r
268 Status = EmmcSendStatus (Device, Slot + 1, &DevStatus);\r
269 if (EFI_ERROR (Status)) {\r
270 return Status;\r
271 }\r
272 //\r
273 // Deselect the device to force it enter stby mode before getting CSD\r
274 // register content.\r
275 // Note here we don't judge return status as some EMMC devices return\r
276 // error but the state has been stby.\r
277 //\r
278 EmmcSelect (Device, 0);\r
279\r
280 Status = EmmcSendStatus (Device, Slot + 1, &DevStatus);\r
281 if (EFI_ERROR (Status)) {\r
282 return Status;\r
283 }\r
284\r
285 Csd = &Device->Csd;\r
286 Status = EmmcGetCsd (Device, Slot + 1, Csd);\r
287 if (EFI_ERROR (Status)) {\r
288 return Status;\r
289 }\r
290 DumpCsd (Csd);\r
291\r
292 if ((Csd->CSizeLow | Csd->CSizeHigh << 2) == 0xFFF) {\r
293 Device->SectorAddressing = TRUE;\r
294 } else {\r
295 Device->SectorAddressing = FALSE;\r
296 }\r
297\r
298 Cid = &Device->Cid;\r
299 Status = EmmcGetCid (Device, Slot + 1, Cid);\r
300 if (EFI_ERROR (Status)) {\r
301 return Status;\r
302 }\r
303\r
304 Status = EmmcSelect (Device, Slot + 1);\r
305 if (EFI_ERROR (Status)) {\r
306 return Status;\r
307 }\r
308\r
309 ExtCsd = &Device->ExtCsd;\r
310 Status = EmmcGetExtCsd (Device, ExtCsd);\r
311 if (EFI_ERROR (Status)) {\r
312 return Status;\r
313 }\r
314 DumpExtCsd (ExtCsd);\r
315\r
316 if (ExtCsd->ExtCsdRev < 5) {\r
317 DEBUG ((EFI_D_ERROR, "The EMMC device version is too low, we don't support!!!\n"));\r
318 return EFI_UNSUPPORTED;\r
319 }\r
320\r
321 if ((ExtCsd->PartitioningSupport & BIT0) != BIT0) {\r
322 DEBUG ((EFI_D_ERROR, "The EMMC device doesn't support Partition Feature!!!\n"));\r
323 return EFI_UNSUPPORTED;\r
324 }\r
325\r
326 for (Index = 0; Index < EMMC_MAX_PARTITIONS; Index++) {\r
327 Partition = &Device->Partition[Index];\r
328 CopyMem (Partition, &mEmmcPartitionTemplate, sizeof (EMMC_PARTITION));\r
329 Partition->Device = Device;\r
330 InitializeListHead (&Partition->Queue);\r
331 Partition->BlockIo.Media = &Partition->BlockMedia;\r
332 Partition->BlockIo2.Media = &Partition->BlockMedia;\r
333 Partition->PartitionType = Index;\r
334 Partition->BlockMedia.IoAlign = Device->Private->PassThru->IoAlign;\r
335 Partition->BlockMedia.BlockSize = 0x200;\r
336 Partition->BlockMedia.LastBlock = 0x00;\r
337 Partition->BlockMedia.RemovableMedia = FALSE;\r
338 Partition->BlockMedia.MediaPresent = TRUE;\r
339 Partition->BlockMedia.LogicalPartition = FALSE;\r
340\r
341 switch (Index) {\r
342 case EmmcPartitionUserData:\r
343 SecCount = *(UINT32*)&ExtCsd->SecCount;\r
344 Capacity = MultU64x32 ((UINT64) SecCount, 0x200);\r
345 break;\r
346 case EmmcPartitionBoot1:\r
347 case EmmcPartitionBoot2:\r
348 Capacity = ExtCsd->BootSizeMult * SIZE_128KB;\r
349 break;\r
350 case EmmcPartitionRPMB:\r
351 Capacity = ExtCsd->RpmbSizeMult * SIZE_128KB;\r
352 break;\r
353 case EmmcPartitionGP1:\r
354 GpSizeMult = (UINT32)(ExtCsd->GpSizeMult[0] | (ExtCsd->GpSizeMult[1] << 8) | (ExtCsd->GpSizeMult[2] << 16));\r
355 Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);\r
356 break;\r
357 case EmmcPartitionGP2:\r
358 GpSizeMult = (UINT32)(ExtCsd->GpSizeMult[3] | (ExtCsd->GpSizeMult[4] << 8) | (ExtCsd->GpSizeMult[5] << 16));\r
359 Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);\r
360 break;\r
361 case EmmcPartitionGP3:\r
362 GpSizeMult = (UINT32)(ExtCsd->GpSizeMult[6] | (ExtCsd->GpSizeMult[7] << 8) | (ExtCsd->GpSizeMult[8] << 16));\r
363 Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);\r
364 break;\r
365 case EmmcPartitionGP4:\r
366 GpSizeMult = (UINT32)(ExtCsd->GpSizeMult[9] | (ExtCsd->GpSizeMult[10] << 8) | (ExtCsd->GpSizeMult[11] << 16));\r
367 Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);\r
368 break;\r
369 default:\r
370 ASSERT (FALSE);\r
371 return EFI_INVALID_PARAMETER;\r
372 }\r
373\r
374 if (Capacity != 0) {\r
375 Partition->Enable = TRUE;\r
376 Partition->BlockMedia.LastBlock = DivU64x32 (Capacity, Partition->BlockMedia.BlockSize) - 1;\r
377 }\r
275d5136
FT
378\r
379 if ((ExtCsd->EraseGroupDef & BIT0) == 0) {\r
380 if (Csd->WriteBlLen < 9) {\r
381 Partition->EraseBlock.EraseLengthGranularity = 1;\r
382 } else {\r
383 Partition->EraseBlock.EraseLengthGranularity = (Csd->EraseGrpMult + 1) * (Csd->EraseGrpSize + 1) * (1 << (Csd->WriteBlLen - 9));\r
384 }\r
385 } else {\r
386 Partition->EraseBlock.EraseLengthGranularity = 1024 * ExtCsd->HcEraseGrpSize;\r
387 }\r
48555339
FT
388 }\r
389\r
390 return EFI_SUCCESS;\r
391}\r
392\r
393/**\r
394 Install BlkIo, BlkIo2 and Ssp protocols for the specified partition in the EMMC device.\r
395\r
396 @param[in] Device The pointer to the EMMC_DEVICE data structure.\r
397 @param[in] Index The index of the partition.\r
398\r
399 @retval EFI_SUCCESS The protocols are installed successfully.\r
400 @retval Others Some error occurs when installing the protocols.\r
401\r
402**/\r
403EFI_STATUS\r
404InstallProtocolOnPartition (\r
405 IN EMMC_DEVICE *Device,\r
406 IN UINT8 Index\r
407 )\r
408{\r
409 EFI_STATUS Status;\r
410 EMMC_PARTITION *Partition;\r
411 CONTROLLER_DEVICE_PATH ControlNode;\r
412 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
413 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
414 EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;\r
415 EFI_HANDLE DeviceHandle;\r
416\r
417 //\r
418 // Build device path\r
419 //\r
420 ParentDevicePath = Device->DevicePath;\r
421\r
422 ControlNode.Header.Type = HARDWARE_DEVICE_PATH;\r
423 ControlNode.Header.SubType = HW_CONTROLLER_DP;\r
424 SetDevicePathNodeLength (&ControlNode.Header, sizeof (CONTROLLER_DEVICE_PATH));\r
425 ControlNode.ControllerNumber = Index;\r
426\r
427 DevicePath = AppendDevicePathNode (ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL*)&ControlNode);\r
428 if (DevicePath == NULL) {\r
429 Status = EFI_OUT_OF_RESOURCES;\r
430 goto Error;\r
431 }\r
432\r
433 DeviceHandle = NULL;\r
434 RemainingDevicePath = DevicePath;\r
435 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);\r
436 if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {\r
437 Status = EFI_ALREADY_STARTED;\r
438 goto Error;\r
439 }\r
440\r
441 Partition = &Device->Partition[Index];\r
442 Partition->DevicePath = DevicePath;\r
443 if (Partition->Enable) {\r
444 //\r
445 // Install BlkIo/BlkIo2/Ssp for the specified partition\r
446 //\r
275d5136 447 if (Partition->PartitionType != EmmcPartitionRPMB) {\r
a4c5a436 448 Status = gBS->InstallMultipleProtocolInterfaces (\r
275d5136 449 &Partition->Handle,\r
a4c5a436
FT
450 &gEfiDevicePathProtocolGuid,\r
451 Partition->DevicePath,\r
452 &gEfiBlockIoProtocolGuid,\r
453 &Partition->BlockIo,\r
454 &gEfiBlockIo2ProtocolGuid,\r
455 &Partition->BlockIo2,\r
275d5136 456 &gEfiEraseBlockProtocolGuid,\r
a4c5a436 457 &Partition->EraseBlock,\r
19b2cb5c
HW
458 &gEfiDiskInfoProtocolGuid,\r
459 &Partition->DiskInfo,\r
a4c5a436 460 NULL\r
275d5136
FT
461 );\r
462 if (EFI_ERROR (Status)) {\r
275d5136
FT
463 goto Error;\r
464 }\r
275d5136 465\r
a4c5a436
FT
466 if (((Partition->PartitionType == EmmcPartitionUserData) ||\r
467 (Partition->PartitionType == EmmcPartitionBoot1) ||\r
468 (Partition->PartitionType == EmmcPartitionBoot2)) &&\r
469 ((Device->Csd.Ccc & BIT10) != 0)) {\r
470 Status = gBS->InstallProtocolInterface (\r
471 &Partition->Handle,\r
472 &gEfiStorageSecurityCommandProtocolGuid,\r
473 EFI_NATIVE_INTERFACE,\r
474 &Partition->StorageSecurity\r
475 );\r
476 if (EFI_ERROR (Status)) {\r
477 gBS->UninstallMultipleProtocolInterfaces (\r
478 &Partition->Handle,\r
479 &gEfiDevicePathProtocolGuid,\r
480 Partition->DevicePath,\r
481 &gEfiBlockIoProtocolGuid,\r
482 &Partition->BlockIo,\r
483 &gEfiBlockIo2ProtocolGuid,\r
484 &Partition->BlockIo2,\r
485 &gEfiEraseBlockProtocolGuid,\r
486 &Partition->EraseBlock,\r
19b2cb5c
HW
487 &gEfiDiskInfoProtocolGuid,\r
488 &Partition->DiskInfo,\r
a4c5a436
FT
489 NULL\r
490 );\r
491 goto Error;\r
492 }\r
48555339 493 }\r
a4c5a436
FT
494\r
495 gBS->OpenProtocol (\r
496 Device->Private->Controller,\r
497 &gEfiSdMmcPassThruProtocolGuid,\r
498 (VOID **) &(Device->Private->PassThru),\r
499 Device->Private->DriverBindingHandle,\r
500 Partition->Handle,\r
501 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
d1102dba 502 );\r
48555339
FT
503 }\r
504\r
48555339
FT
505 } else {\r
506 Status = EFI_INVALID_PARAMETER;\r
507 }\r
508\r
509Error:\r
510 if (EFI_ERROR (Status) && (DevicePath != NULL)) {\r
511 FreePool (DevicePath);\r
512 }\r
513\r
514 return Status;\r
515}\r
516\r
517/**\r
518 Scan EMMC Bus to discover the device.\r
519\r
520 @param[in] Private The EMMC driver private data structure.\r
521 @param[in] Slot The slot number to check device present.\r
5e71d5cf 522 @param[in] RemainingDevicePath The pointer to the remaining device path.\r
48555339
FT
523\r
524 @retval EFI_SUCCESS Successfully to discover the device and attach\r
525 SdMmcIoProtocol to it.\r
526 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
527 of resources.\r
528 @retval EFI_ALREADY_STARTED The device was discovered before.\r
529 @retval Others Fail to discover the device.\r
530\r
531**/\r
532EFI_STATUS\r
533EFIAPI\r
534DiscoverEmmcDevice (\r
535 IN EMMC_DRIVER_PRIVATE_DATA *Private,\r
536 IN UINT8 Slot,\r
537 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
538 )\r
539{\r
540 EFI_STATUS Status;\r
541 EMMC_DEVICE *Device;\r
542 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
543 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
544 EFI_DEVICE_PATH_PROTOCOL *RemainingEmmcDevPath;\r
545 EFI_DEV_PATH *Node;\r
546 EFI_HANDLE DeviceHandle;\r
547 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
548 UINT8 Index;\r
549\r
550 Device = NULL;\r
551 DevicePath = NULL;\r
552 NewDevicePath = NULL;\r
553 RemainingDevicePath = NULL;\r
554 PassThru = Private->PassThru;\r
555 Device = &Private->Device[Slot];\r
556\r
557 //\r
558 // Build Device Path to check if the EMMC device present at the slot.\r
559 //\r
560 Status = PassThru->BuildDevicePath (\r
561 PassThru,\r
562 Slot,\r
563 &DevicePath\r
564 );\r
565 if (EFI_ERROR(Status)) {\r
566 return Status;\r
567 }\r
568\r
569 if (DevicePath->SubType != MSG_EMMC_DP) {\r
570 Status = EFI_UNSUPPORTED;\r
571 goto Error;\r
572 }\r
573\r
574 NewDevicePath = AppendDevicePathNode (\r
575 Private->ParentDevicePath,\r
576 DevicePath\r
577 );\r
578 if (NewDevicePath == NULL) {\r
579 Status = EFI_OUT_OF_RESOURCES;\r
580 goto Error;\r
581 }\r
582\r
583 DeviceHandle = NULL;\r
584 RemainingEmmcDevPath = NewDevicePath;\r
585 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingEmmcDevPath, &DeviceHandle);\r
586 //\r
587 // The device path to the EMMC device doesn't exist. It means the corresponding device private data hasn't been initialized.\r
588 //\r
589 if (EFI_ERROR (Status) || (DeviceHandle == NULL) || !IsDevicePathEnd (RemainingEmmcDevPath)) {\r
590 Device->DevicePath = NewDevicePath;\r
591 Device->Slot = Slot;\r
592 Device->Private = Private;\r
593 //\r
594 // Expose user area in the Sd memory card to upper layer.\r
595 //\r
596 Status = DiscoverAllPartitions (Device);\r
597 if (EFI_ERROR(Status)) {\r
598 FreePool (NewDevicePath);\r
599 goto Error;\r
600 }\r
601\r
602 Status = gBS->InstallProtocolInterface (\r
603 &Device->Handle,\r
604 &gEfiDevicePathProtocolGuid,\r
605 EFI_NATIVE_INTERFACE,\r
606 Device->DevicePath\r
607 );\r
608 if (EFI_ERROR(Status)) {\r
609 FreePool (NewDevicePath);\r
610 goto Error;\r
611 }\r
612\r
613 Device->ControllerNameTable = NULL;\r
614 GetEmmcModelName (Device, &Device->Cid);\r
615 AddUnicodeString2 (\r
616 "eng",\r
617 gEmmcDxeComponentName.SupportedLanguages,\r
618 &Device->ControllerNameTable,\r
619 Device->ModelName,\r
620 TRUE\r
621 );\r
622 AddUnicodeString2 (\r
623 "en",\r
e25a7678 624 gEmmcDxeComponentName2.SupportedLanguages,\r
48555339
FT
625 &Device->ControllerNameTable,\r
626 Device->ModelName,\r
627 FALSE\r
628 );\r
629 }\r
630\r
631 if (RemainingDevicePath == NULL) {\r
632 //\r
633 // Expose all partitions in the Emmc device to upper layer.\r
634 //\r
635 for (Index = 0; Index < EMMC_MAX_PARTITIONS; Index++) {\r
636 InstallProtocolOnPartition (Device, Index);\r
637 }\r
638 } else if (!IsDevicePathEnd (RemainingDevicePath)) {\r
639 //\r
640 // Enumerate the specified partition\r
641 //\r
642 Node = (EFI_DEV_PATH *) RemainingDevicePath;\r
643 if ((DevicePathType (&Node->DevPath) != HARDWARE_DEVICE_PATH) ||\r
644 (DevicePathSubType (&Node->DevPath) != HW_CONTROLLER_DP) ||\r
645 (DevicePathNodeLength (&Node->DevPath) != sizeof (CONTROLLER_DEVICE_PATH))) {\r
646 Status = EFI_INVALID_PARAMETER;\r
647 goto Error;\r
648 }\r
649\r
650 Index = (UINT8)Node->Controller.ControllerNumber;\r
651 if (Index >= EMMC_MAX_PARTITIONS) {\r
652 Status = EFI_INVALID_PARAMETER;\r
653 goto Error;\r
654 }\r
655\r
656 Status = InstallProtocolOnPartition (Device, Index);\r
657 }\r
658\r
659Error:\r
660 FreePool (DevicePath);\r
661\r
662 return Status;\r
663}\r
664\r
665/**\r
666 Tests to see if this driver supports a given controller. If a child device is provided,\r
667 it further tests to see if this driver supports creating a handle for the specified child device.\r
668\r
669 This function checks to see if the driver specified by This supports the device specified by\r
670 ControllerHandle. Drivers will typically use the device path attached to\r
671 ControllerHandle and/or the services from the bus I/O abstraction attached to\r
672 ControllerHandle to determine if the driver supports ControllerHandle. This function\r
673 may be called many times during platform initialization. In order to reduce boot times, the tests\r
674 performed by this function must be very small, and take as little time as possible to execute. This\r
675 function must not change the state of any hardware devices, and this function must be aware that the\r
676 device specified by ControllerHandle may already be managed by the same driver or a\r
677 different driver. This function must match its calls to AllocatePages() with FreePages(),\r
678 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
679 Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
680 already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
681 to guarantee the state of ControllerHandle is not modified by this function.\r
682\r
683 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
684 @param[in] ControllerHandle The handle of the controller to test. This handle\r
685 must support a protocol interface that supplies\r
686 an I/O abstraction to the driver.\r
687 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
688 parameter is ignored by device drivers, and is optional for bus\r
689 drivers. For bus drivers, if this parameter is not NULL, then\r
690 the bus driver must determine if the bus controller specified\r
691 by ControllerHandle and the child controller specified\r
692 by RemainingDevicePath are both supported by this\r
693 bus driver.\r
694\r
695 @retval EFI_SUCCESS The device specified by ControllerHandle and\r
696 RemainingDevicePath is supported by the driver specified by This.\r
697 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
698 RemainingDevicePath is already being managed by the driver\r
699 specified by This.\r
700 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
701 RemainingDevicePath is already being managed by a different\r
702 driver or an application that requires exclusive access.\r
703 Currently not implemented.\r
704 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
705 RemainingDevicePath is not supported by the driver specified by This.\r
706**/\r
707EFI_STATUS\r
708EFIAPI\r
709EmmcDxeDriverBindingSupported (\r
710 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
711 IN EFI_HANDLE Controller,\r
712 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
713 )\r
714{\r
715 EFI_STATUS Status;\r
716 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
717 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
718 UINT8 Slot;\r
719\r
720 //\r
721 // Test EFI_SD_MMC_PASS_THRU_PROTOCOL on the controller handle.\r
722 //\r
723 Status = gBS->OpenProtocol (\r
724 Controller,\r
725 &gEfiSdMmcPassThruProtocolGuid,\r
726 (VOID**) &PassThru,\r
727 This->DriverBindingHandle,\r
728 Controller,\r
729 EFI_OPEN_PROTOCOL_BY_DRIVER\r
730 );\r
731\r
732 if (Status == EFI_ALREADY_STARTED) {\r
733 return EFI_SUCCESS;\r
734 }\r
735\r
736 if (EFI_ERROR (Status)) {\r
737 return Status;\r
738 }\r
739\r
740 //\r
741 // Test RemainingDevicePath is valid or not.\r
742 //\r
743 if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {\r
744 Status = PassThru->GetSlotNumber (PassThru, RemainingDevicePath, &Slot);\r
745 if (EFI_ERROR (Status)) {\r
746 //\r
747 // Close the I/O Abstraction(s) used to perform the supported test\r
748 //\r
749 gBS->CloseProtocol (\r
750 Controller,\r
751 &gEfiSdMmcPassThruProtocolGuid,\r
752 This->DriverBindingHandle,\r
753 Controller\r
754 );\r
755 return Status;\r
756 }\r
757 }\r
758\r
759 //\r
760 // Close the I/O Abstraction(s) used to perform the supported test\r
761 //\r
762 gBS->CloseProtocol (\r
763 Controller,\r
764 &gEfiSdMmcPassThruProtocolGuid,\r
765 This->DriverBindingHandle,\r
766 Controller\r
767 );\r
768\r
769 //\r
770 // Open the EFI Device Path protocol needed to perform the supported test\r
771 //\r
772 Status = gBS->OpenProtocol (\r
773 Controller,\r
774 &gEfiDevicePathProtocolGuid,\r
775 (VOID **) &ParentDevicePath,\r
776 This->DriverBindingHandle,\r
777 Controller,\r
778 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
779 );\r
780 return Status;\r
781}\r
782\r
783/**\r
784 Starts a device controller or a bus controller.\r
785\r
786 The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
787 As a result, much of the error checking on the parameters to Start() has been moved into this\r
788 common boot service. It is legal to call Start() from other locations,\r
789 but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
790 1. ControllerHandle must be a valid EFI_HANDLE.\r
791 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
792 EFI_DEVICE_PATH_PROTOCOL.\r
793 3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
794 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
795\r
796 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
797 @param[in] ControllerHandle The handle of the controller to start. This handle\r
798 must support a protocol interface that supplies\r
799 an I/O abstraction to the driver.\r
800 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
801 parameter is ignored by device drivers, and is optional for bus\r
802 drivers. For a bus driver, if this parameter is NULL, then handles\r
803 for all the children of Controller are created by this driver.\r
804 If this parameter is not NULL and the first Device Path Node is\r
805 not the End of Device Path Node, then only the handle for the\r
806 child device specified by the first Device Path Node of\r
807 RemainingDevicePath is created by this driver.\r
808 If the first Device Path Node of RemainingDevicePath is\r
809 the End of Device Path Node, no child handle is created by this\r
810 driver.\r
811\r
812 @retval EFI_SUCCESS The device was started.\r
813 @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.\r
814 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
815 @retval Others The driver failded to start the device.\r
816\r
817**/\r
818EFI_STATUS\r
819EFIAPI\r
820EmmcDxeDriverBindingStart (\r
821 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
822 IN EFI_HANDLE Controller,\r
823 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
824 )\r
825{\r
826 EFI_STATUS Status;\r
827 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
828 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
829 EMMC_DRIVER_PRIVATE_DATA *Private;\r
830 UINT8 Slot;\r
831\r
832 Private = NULL;\r
833 PassThru = NULL;\r
834 Status = gBS->OpenProtocol (\r
835 Controller,\r
836 &gEfiSdMmcPassThruProtocolGuid,\r
837 (VOID **) &PassThru,\r
838 This->DriverBindingHandle,\r
839 Controller,\r
840 EFI_OPEN_PROTOCOL_BY_DRIVER\r
841 );\r
842 if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {\r
843 return Status;\r
844 }\r
845\r
846 //\r
847 // Check EFI_ALREADY_STARTED to reuse the original EMMC_DRIVER_PRIVATE_DATA.\r
848 //\r
849 if (Status != EFI_ALREADY_STARTED) {\r
850 Private = AllocateZeroPool (sizeof (EMMC_DRIVER_PRIVATE_DATA));\r
851 if (Private == NULL) {\r
852 Status = EFI_OUT_OF_RESOURCES;\r
853 goto Error;\r
854 }\r
855\r
856 Status = gBS->OpenProtocol (\r
857 Controller,\r
858 &gEfiDevicePathProtocolGuid,\r
859 (VOID **) &ParentDevicePath,\r
860 This->DriverBindingHandle,\r
861 Controller,\r
862 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
863 );\r
864 ASSERT_EFI_ERROR (Status);\r
865 Private->PassThru = PassThru;\r
866 Private->Controller = Controller;\r
867 Private->ParentDevicePath = ParentDevicePath;\r
868 Private->DriverBindingHandle = This->DriverBindingHandle;\r
869\r
870 Status = gBS->InstallProtocolInterface (\r
871 &Controller,\r
872 &gEfiCallerIdGuid,\r
873 EFI_NATIVE_INTERFACE,\r
874 Private\r
875 );\r
876 if (EFI_ERROR (Status)) {\r
877 goto Error;\r
878 }\r
879 } else {\r
880 Status = gBS->OpenProtocol (\r
881 Controller,\r
882 &gEfiCallerIdGuid,\r
883 (VOID **) &Private,\r
884 This->DriverBindingHandle,\r
885 Controller,\r
886 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
887 );\r
888 if (EFI_ERROR (Status)) {\r
889 goto Error;\r
890 }\r
891 }\r
892\r
893 if (RemainingDevicePath == NULL) {\r
894 Slot = 0xFF;\r
895 while (TRUE) {\r
896 Status = PassThru->GetNextSlot (PassThru, &Slot);\r
897 if (EFI_ERROR (Status)) {\r
898 //\r
899 // Cannot find more legal slots.\r
900 //\r
901 Status = EFI_SUCCESS;\r
902 break;\r
903 }\r
904\r
905 Status = DiscoverEmmcDevice (Private, Slot, NULL);\r
906 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
907 break;\r
908 }\r
909 }\r
910 } else if (!IsDevicePathEnd (RemainingDevicePath)) {\r
911 Status = PassThru->GetSlotNumber (PassThru, RemainingDevicePath, &Slot);\r
912 if (!EFI_ERROR (Status)) {\r
913 Status = DiscoverEmmcDevice (Private, Slot, NextDevicePathNode (RemainingDevicePath));\r
914 }\r
915 }\r
916\r
917Error:\r
918 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
919 gBS->CloseProtocol (\r
920 Controller,\r
921 &gEfiSdMmcPassThruProtocolGuid,\r
922 This->DriverBindingHandle,\r
923 Controller\r
924 );\r
925\r
926 if (Private != NULL) {\r
927 gBS->UninstallMultipleProtocolInterfaces (\r
928 Controller,\r
929 &gEfiCallerIdGuid,\r
930 Private,\r
931 NULL\r
932 );\r
933 FreePool (Private);\r
934 }\r
935 }\r
936 return Status;\r
937}\r
938\r
939/**\r
940 Stops a device controller or a bus controller.\r
941\r
942 The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
943 As a result, much of the error checking on the parameters to Stop() has been moved\r
944 into this common boot service. It is legal to call Stop() from other locations,\r
945 but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
946 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
947 same driver's Start() function.\r
948 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
949 EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
950 Start() function, and the Start() function must have called OpenProtocol() on\r
951 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
952\r
953 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
954 @param[in] ControllerHandle A handle to the device being stopped. The handle must\r
955 support a bus specific I/O protocol for the driver\r
956 to use to stop the device.\r
957 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.\r
958 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL\r
959 if NumberOfChildren is 0.\r
960\r
961 @retval EFI_SUCCESS The device was stopped.\r
962 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
963\r
964**/\r
965EFI_STATUS\r
966EFIAPI\r
967EmmcDxeDriverBindingStop (\r
968 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
969 IN EFI_HANDLE Controller,\r
970 IN UINTN NumberOfChildren,\r
971 IN EFI_HANDLE *ChildHandleBuffer\r
972 )\r
973{\r
974 EFI_STATUS Status;\r
975 BOOLEAN AllChildrenStopped;\r
976 UINTN Index;\r
977 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
978 EMMC_DRIVER_PRIVATE_DATA *Private;\r
979 EMMC_DEVICE *Device;\r
980 EMMC_PARTITION *Partition;\r
981 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
982 EFI_BLOCK_IO2_PROTOCOL *BlockIo2;\r
983 EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *StorageSecurity;\r
984 LIST_ENTRY *Link;\r
985 LIST_ENTRY *NextLink;\r
986 EMMC_REQUEST *Request;\r
987\r
988 BlockIo = NULL;\r
989 BlockIo2 = NULL;\r
990 if (NumberOfChildren == 0) {\r
991 Status = gBS->OpenProtocol (\r
992 Controller,\r
993 &gEfiCallerIdGuid,\r
994 (VOID **) &Private,\r
995 This->DriverBindingHandle,\r
996 Controller,\r
997 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
998 );\r
999 if (EFI_ERROR (Status)) {\r
1000 return EFI_DEVICE_ERROR;\r
1001 }\r
1002\r
1003 for (Index = 0; Index < EMMC_MAX_DEVICES; Index++) {\r
1004 Device = &Private->Device[Index];\r
1005 Status = gBS->OpenProtocol (\r
1006 Device->Handle,\r
1007 &gEfiDevicePathProtocolGuid,\r
1008 (VOID **) &DevicePath,\r
1009 This->DriverBindingHandle,\r
1010 Controller,\r
1011 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1012 );\r
1013 if (EFI_ERROR (Status)) {\r
1014 continue;\r
1015 }\r
1016 ASSERT (DevicePath == Device->DevicePath);\r
1017 gBS->UninstallProtocolInterface (\r
1018 Device->Handle,\r
1019 &gEfiDevicePathProtocolGuid,\r
1020 DevicePath\r
1021 );\r
1022 FreePool (Device->DevicePath);\r
1023 }\r
1024\r
1025 gBS->UninstallProtocolInterface (\r
1026 Controller,\r
1027 &gEfiCallerIdGuid,\r
1028 Private\r
1029 );\r
1030 gBS->CloseProtocol (\r
1031 Controller,\r
1032 &gEfiSdMmcPassThruProtocolGuid,\r
1033 This->DriverBindingHandle,\r
1034 Controller\r
1035 );\r
1036 FreePool (Private);\r
1037\r
1038 return EFI_SUCCESS;\r
1039 }\r
1040\r
1041 AllChildrenStopped = TRUE;\r
1042\r
1043 for (Index = 0; Index < NumberOfChildren; Index++) {\r
1044 Status = gBS->OpenProtocol (\r
1045 ChildHandleBuffer[Index],\r
1046 &gEfiBlockIoProtocolGuid,\r
1047 (VOID **) &BlockIo,\r
1048 This->DriverBindingHandle,\r
1049 Controller,\r
1050 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1051 );\r
1052 if (EFI_ERROR (Status)) {\r
1053 Status = gBS->OpenProtocol (\r
1054 ChildHandleBuffer[Index],\r
1055 &gEfiBlockIo2ProtocolGuid,\r
1056 (VOID **) &BlockIo2,\r
1057 This->DriverBindingHandle,\r
1058 Controller,\r
1059 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1060 );\r
1061 if (EFI_ERROR (Status)) {\r
1062 AllChildrenStopped = FALSE;\r
1063 continue;\r
1064 }\r
1065 }\r
1066\r
1067 if (BlockIo != NULL) {\r
1068 Partition = EMMC_PARTITION_DATA_FROM_BLKIO (BlockIo);\r
1069 } else {\r
1070 ASSERT (BlockIo2 != NULL);\r
1071 Partition = EMMC_PARTITION_DATA_FROM_BLKIO2 (BlockIo2);\r
1072 }\r
1073\r
1074 for (Link = GetFirstNode (&Partition->Queue);\r
1075 !IsNull (&Partition->Queue, Link);\r
1076 Link = NextLink) {\r
1077 NextLink = GetNextNode (&Partition->Queue, Link);\r
1078\r
1079 RemoveEntryList (Link);\r
1080 Request = EMMC_REQUEST_FROM_LINK (Link);\r
1081\r
1082 gBS->CloseEvent (Request->Event);\r
1083 Request->Token->TransactionStatus = EFI_ABORTED;\r
1084\r
1085 if (Request->IsEnd) {\r
1086 gBS->SignalEvent (Request->Token->Event);\r
1087 }\r
1088\r
1089 FreePool (Request);\r
1090 }\r
1091\r
1092 //\r
1093 // Close the child handle\r
1094 //\r
1095 Status = gBS->CloseProtocol (\r
1096 Controller,\r
1097 &gEfiSdMmcPassThruProtocolGuid,\r
1098 This->DriverBindingHandle,\r
1099 ChildHandleBuffer[Index]\r
1100 );\r
1101\r
1102 Status = gBS->UninstallMultipleProtocolInterfaces (\r
1103 ChildHandleBuffer[Index],\r
1104 &gEfiDevicePathProtocolGuid,\r
1105 Partition->DevicePath,\r
1106 &gEfiBlockIoProtocolGuid,\r
1107 &Partition->BlockIo,\r
1108 &gEfiBlockIo2ProtocolGuid,\r
1109 &Partition->BlockIo2,\r
a4c5a436
FT
1110 &gEfiEraseBlockProtocolGuid,\r
1111 &Partition->EraseBlock,\r
19b2cb5c
HW
1112 &gEfiDiskInfoProtocolGuid,\r
1113 &Partition->DiskInfo,\r
48555339
FT
1114 NULL\r
1115 );\r
1116 if (EFI_ERROR (Status)) {\r
1117 AllChildrenStopped = FALSE;\r
1118 gBS->OpenProtocol (\r
1119 Controller,\r
1120 &gEfiSdMmcPassThruProtocolGuid,\r
1121 (VOID **)&Partition->Device->Private->PassThru,\r
1122 This->DriverBindingHandle,\r
1123 ChildHandleBuffer[Index],\r
1124 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
1125 );\r
1126 continue;\r
1127 }\r
1128\r
1129 //\r
1130 // If Storage Security Command Protocol is installed, then uninstall this protocol.\r
1131 //\r
1132 Status = gBS->OpenProtocol (\r
1133 ChildHandleBuffer[Index],\r
1134 &gEfiStorageSecurityCommandProtocolGuid,\r
1135 (VOID **) &StorageSecurity,\r
1136 This->DriverBindingHandle,\r
1137 Controller,\r
1138 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1139 );\r
1140\r
1141 if (!EFI_ERROR (Status)) {\r
1142 Status = gBS->UninstallProtocolInterface (\r
1143 ChildHandleBuffer[Index],\r
1144 &gEfiStorageSecurityCommandProtocolGuid,\r
1145 &Partition->StorageSecurity\r
1146 );\r
1147 if (EFI_ERROR (Status)) {\r
1148 gBS->OpenProtocol (\r
1149 Controller,\r
1150 &gEfiSdMmcPassThruProtocolGuid,\r
1151 (VOID **) &Partition->Device->Private->PassThru,\r
1152 This->DriverBindingHandle,\r
1153 ChildHandleBuffer[Index],\r
1154 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
1155 );\r
1156 AllChildrenStopped = FALSE;\r
1157 continue;\r
1158 }\r
1159 }\r
1160\r
1161 FreePool (Partition->DevicePath);\r
1162 }\r
1163\r
1164 if (!AllChildrenStopped) {\r
1165 return EFI_DEVICE_ERROR;\r
1166 }\r
1167\r
1168 return EFI_SUCCESS;\r
1169}\r
1170\r
1171/**\r
1172 The user Entry Point for module EmmcDxe. The user code starts with this function.\r
1173\r
1174 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
1175 @param[in] SystemTable A pointer to the EFI System Table.\r
1176\r
1177 @retval EFI_SUCCESS The entry point is executed successfully.\r
1178 @retval other Some errors occur when executing this entry point.\r
1179\r
1180**/\r
1181EFI_STATUS\r
1182EFIAPI\r
1183InitializeEmmcDxe (\r
1184 IN EFI_HANDLE ImageHandle,\r
1185 IN EFI_SYSTEM_TABLE *SystemTable\r
1186 )\r
1187{\r
1188 EFI_STATUS Status;\r
1189\r
1190 //\r
1191 // Install driver model protocol(s).\r
1192 //\r
1193 Status = EfiLibInstallDriverBindingComponentName2 (\r
1194 ImageHandle,\r
1195 SystemTable,\r
1196 &gEmmcDxeDriverBinding,\r
1197 ImageHandle,\r
1198 &gEmmcDxeComponentName,\r
1199 &gEmmcDxeComponentName2\r
1200 );\r
1201 ASSERT_EFI_ERROR (Status);\r
1202\r
1203 return Status;\r
1204}\r
1205\r