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