]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Sd/SdDxe/SdDxe.c
MdeModulePkg/SdDxe: Implementation of Disk Information Protocol
[mirror_edk2.git] / MdeModulePkg / Bus / Sd / SdDxe / SdDxe.c
CommitLineData
48555339
FT
1/** @file\r
2 The SdDxe driver is used to manage the SD memory card device.\r
3\r
4 It produces BlockIo and BlockIo2 protocols to allow upper layer\r
5 access the SD memory card device.\r
6\r
af6a6bf4 7 Copyright (c) 2015 - 2017, 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 "SdDxe.h"\r
19\r
20//\r
21// SdDxe Driver Binding Protocol Instance\r
22//\r
23EFI_DRIVER_BINDING_PROTOCOL gSdDxeDriverBinding = {\r
24 SdDxeDriverBindingSupported,\r
25 SdDxeDriverBindingStart,\r
26 SdDxeDriverBindingStop,\r
27 0x10,\r
28 NULL,\r
29 NULL\r
30};\r
31\r
32//\r
33// Template for SD_DEVICE data structure.\r
34//\r
35SD_DEVICE mSdDeviceTemplate = {\r
36 SD_DEVICE_SIGNATURE, // Signature\r
37 NULL, // Handle\r
38 NULL, // DevicePath\r
39 0xFF, // Slot\r
40 FALSE, // SectorAddressing\r
41 { // BlockIo\r
42 EFI_BLOCK_IO_PROTOCOL_REVISION,\r
43 NULL,\r
44 SdReset,\r
45 SdReadBlocks,\r
46 SdWriteBlocks,\r
47 SdFlushBlocks\r
48 },\r
49 { // BlockIo2\r
50 NULL,\r
51 SdResetEx,\r
52 SdReadBlocksEx,\r
53 SdWriteBlocksEx,\r
54 SdFlushBlocksEx\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
275d5136
FT
67 { // EraseBlock\r
68 EFI_ERASE_BLOCK_PROTOCOL_REVISION,\r
69 1,\r
70 SdEraseBlocks\r
71 },\r
af6a6bf4
HW
72 { // DiskInfo\r
73 EFI_DISK_INFO_SD_MMC_INTERFACE_GUID,\r
74 SdDiskInfoInquiry,\r
75 SdDiskInfoIdentify,\r
76 SdDiskInfoSenseData,\r
77 SdDiskInfoWhichIde\r
78 },\r
48555339
FT
79 { // Queue\r
80 NULL,\r
81 NULL\r
82 },\r
83 { // Csd\r
84 0,\r
85 },\r
86 { // Cid\r
87 0,\r
88 },\r
89 NULL, // ControllerNameTable\r
90 { // ModelName\r
91 0,\r
92 },\r
93 NULL // Private\r
94};\r
95\r
96/**\r
97 Decode and print SD CSD Register content.\r
98\r
99 @param[in] Csd Pointer to SD_CSD data structure.\r
100\r
101 @retval EFI_SUCCESS The function completed successfully\r
102**/\r
103EFI_STATUS\r
104DumpCsd (\r
105 IN SD_CSD *Csd\r
106 )\r
107{\r
108 SD_CSD2 *Csd2;\r
109\r
110 DEBUG((DEBUG_INFO, "== Dump Sd Csd Register==\n"));\r
111 DEBUG((DEBUG_INFO, " CSD structure 0x%x\n", Csd->CsdStructure));\r
112 DEBUG((DEBUG_INFO, " Data read access-time 1 0x%x\n", Csd->Taac));\r
113 DEBUG((DEBUG_INFO, " Data read access-time 2 0x%x\n", Csd->Nsac));\r
114 DEBUG((DEBUG_INFO, " Max. bus clock frequency 0x%x\n", Csd->TranSpeed));\r
115 DEBUG((DEBUG_INFO, " Device command classes 0x%x\n", Csd->Ccc));\r
116 DEBUG((DEBUG_INFO, " Max. read data block length 0x%x\n", Csd->ReadBlLen));\r
117 DEBUG((DEBUG_INFO, " Partial blocks for read allowed 0x%x\n", Csd->ReadBlPartial));\r
118 DEBUG((DEBUG_INFO, " Write block misalignment 0x%x\n", Csd->WriteBlkMisalign));\r
119 DEBUG((DEBUG_INFO, " Read block misalignment 0x%x\n", Csd->ReadBlkMisalign));\r
120 DEBUG((DEBUG_INFO, " DSR implemented 0x%x\n", Csd->DsrImp));\r
121 if (Csd->CsdStructure == 0) {\r
122 DEBUG((DEBUG_INFO, " Device size 0x%x\n", Csd->CSizeLow | (Csd->CSizeHigh << 2)));\r
123 DEBUG((DEBUG_INFO, " Max. read current @ VDD min 0x%x\n", Csd->VddRCurrMin));\r
124 DEBUG((DEBUG_INFO, " Max. read current @ VDD max 0x%x\n", Csd->VddRCurrMax));\r
125 DEBUG((DEBUG_INFO, " Max. write current @ VDD min 0x%x\n", Csd->VddWCurrMin));\r
126 DEBUG((DEBUG_INFO, " Max. write current @ VDD max 0x%x\n", Csd->VddWCurrMax));\r
127 } else {\r
128 Csd2 = (SD_CSD2*)(VOID*)Csd;\r
129 DEBUG((DEBUG_INFO, " Device size 0x%x\n", Csd2->CSizeLow | (Csd->CSizeHigh << 16)));\r
130 }\r
131 DEBUG((DEBUG_INFO, " Erase sector size 0x%x\n", Csd->SectorSize));\r
132 DEBUG((DEBUG_INFO, " Erase single block enable 0x%x\n", Csd->EraseBlkEn));\r
133 DEBUG((DEBUG_INFO, " Write protect group size 0x%x\n", Csd->WpGrpSize));\r
134 DEBUG((DEBUG_INFO, " Write protect group enable 0x%x\n", Csd->WpGrpEnable));\r
135 DEBUG((DEBUG_INFO, " Write speed factor 0x%x\n", Csd->R2WFactor));\r
136 DEBUG((DEBUG_INFO, " Max. write data block length 0x%x\n", Csd->WriteBlLen));\r
137 DEBUG((DEBUG_INFO, " Partial blocks for write allowed 0x%x\n", Csd->WriteBlPartial));\r
138 DEBUG((DEBUG_INFO, " File format group 0x%x\n", Csd->FileFormatGrp));\r
139 DEBUG((DEBUG_INFO, " Copy flag (OTP) 0x%x\n", Csd->Copy));\r
140 DEBUG((DEBUG_INFO, " Permanent write protection 0x%x\n", Csd->PermWriteProtect));\r
141 DEBUG((DEBUG_INFO, " Temporary write protection 0x%x\n", Csd->TmpWriteProtect));\r
142 DEBUG((DEBUG_INFO, " File format 0x%x\n", Csd->FileFormat));\r
143\r
144 return EFI_SUCCESS;\r
145}\r
146\r
147/**\r
148 Get SD device model name.\r
149\r
150 @param[in, out] Device The pointer to the SD_DEVICE data structure.\r
151 @param[in] Cid Pointer to SD_CID data structure.\r
152\r
153 @retval EFI_SUCCESS The function completed successfully\r
154\r
155**/\r
156EFI_STATUS\r
157GetSdModelName (\r
158 IN OUT SD_DEVICE *Device,\r
159 IN SD_CID *Cid\r
160 )\r
161{\r
162 CHAR8 String[SD_MODEL_NAME_MAX_LEN];\r
163\r
164 ZeroMem (String, sizeof (String));\r
165 CopyMem (String, Cid->OemId, sizeof (Cid->OemId));\r
166 String[sizeof (Cid->OemId)] = ' ';\r
167 CopyMem (String + sizeof (Cid->OemId) + 1, Cid->ProductName, sizeof (Cid->ProductName));\r
168 String[sizeof (Cid->OemId) + sizeof (Cid->ProductName)] = ' ';\r
169 CopyMem (String + sizeof (Cid->OemId) + sizeof (Cid->ProductName) + 1, Cid->ProductSerialNumber, sizeof (Cid->ProductSerialNumber));\r
170\r
b68ccac1 171 AsciiStrToUnicodeStrS (String, Device->ModelName, sizeof (Device->ModelName) / sizeof (Device->ModelName[0]));\r
48555339
FT
172\r
173 return EFI_SUCCESS;\r
174}\r
175\r
176/**\r
177 Discover user area partition in the SD device.\r
178\r
179 @param[in] Device The pointer to the SD_DEVICE data structure.\r
180\r
181 @retval EFI_SUCCESS The user area partition in the SD device is successfully identified.\r
182 @return Others Some error occurs when identifying the user area.\r
183\r
184**/\r
185EFI_STATUS\r
186DiscoverUserArea (\r
187 IN SD_DEVICE *Device\r
188 )\r
189{\r
190 EFI_STATUS Status;\r
191 SD_CSD *Csd;\r
192 SD_CSD2 *Csd2;\r
193 SD_CID *Cid;\r
194 UINT64 Capacity;\r
195 UINT32 DevStatus;\r
196 UINT16 Rca;\r
197 UINT32 CSize;\r
198 UINT32 CSizeMul;\r
199 UINT32 ReadBlLen;\r
200\r
201 //\r
202 // Deselect the device to force it enter stby mode.\r
203 // Note here we don't judge return status as some SD devices return\r
204 // error but the state has been stby.\r
205 //\r
206 SdSelect (Device, 0);\r
207\r
208 Status = SdSetRca (Device, &Rca);\r
209 if (EFI_ERROR (Status)) {\r
210 DEBUG ((EFI_D_ERROR, "DiscoverUserArea(): Assign new Rca = 0x%x fails with %r\n", Rca, Status));\r
211 return Status;\r
212 }\r
213\r
214 Csd = &Device->Csd;\r
215 Status = SdGetCsd (Device, Rca, Csd);\r
216 if (EFI_ERROR (Status)) {\r
217 return Status;\r
218 }\r
219 DumpCsd (Csd);\r
220\r
221 Cid = &Device->Cid;\r
222 Status = SdGetCid (Device, Rca, Cid);\r
223 if (EFI_ERROR (Status)) {\r
224 return Status;\r
225 }\r
226 GetSdModelName (Device, Cid);\r
227\r
228 Status = SdSelect (Device, Rca);\r
229 if (EFI_ERROR (Status)) {\r
230 DEBUG ((EFI_D_ERROR, "DiscoverUserArea(): Reselect the device 0x%x fails with %r\n", Rca, Status));\r
231 return Status;\r
232 }\r
233\r
234 Status = SdSendStatus (Device, Rca, &DevStatus);\r
235 if (EFI_ERROR (Status)) {\r
236 return Status;\r
237 }\r
238\r
239 if (Csd->CsdStructure == 0) {\r
240 Device->SectorAddressing = FALSE;\r
241 CSize = (Csd->CSizeHigh << 2 | Csd->CSizeLow) + 1;\r
242 CSizeMul = (1 << (Csd->CSizeMul + 2));\r
243 ReadBlLen = (1 << (Csd->ReadBlLen));\r
244 Capacity = MultU64x32 (MultU64x32 ((UINT64)CSize, CSizeMul), ReadBlLen);\r
245 } else {\r
246 Device->SectorAddressing = TRUE;\r
247 Csd2 = (SD_CSD2*)(VOID*)Csd;\r
248 CSize = (Csd2->CSizeHigh << 16 | Csd2->CSizeLow) + 1;\r
249 Capacity = MultU64x32 ((UINT64)CSize, SIZE_512KB);\r
250 }\r
251\r
252 Device->BlockIo.Media = &Device->BlockMedia;\r
253 Device->BlockIo2.Media = &Device->BlockMedia;\r
254 Device->BlockMedia.IoAlign = Device->Private->PassThru->IoAlign;\r
255 Device->BlockMedia.BlockSize = 0x200;\r
256 Device->BlockMedia.LastBlock = 0x00;\r
257 Device->BlockMedia.RemovableMedia = TRUE;\r
258 Device->BlockMedia.MediaPresent = TRUE;\r
259 Device->BlockMedia.LogicalPartition = FALSE;\r
260 Device->BlockMedia.LastBlock = DivU64x32 (Capacity, Device->BlockMedia.BlockSize) - 1;\r
261\r
275d5136
FT
262 if (Csd->EraseBlkEn) {\r
263 Device->EraseBlock.EraseLengthGranularity = 1;\r
264 } else {\r
265 Device->EraseBlock.EraseLengthGranularity = (Csd->SectorSize + 1) * (1 << (Csd->WriteBlLen - 9));\r
266 }\r
267\r
48555339
FT
268 return Status;\r
269}\r
270\r
271/**\r
272 Scan SD Bus to discover the device.\r
273\r
274 @param[in] Private The SD driver private data structure.\r
275 @param[in] Slot The slot number to check device present.\r
276\r
277 @retval EFI_SUCCESS Successfully to discover the device and attach\r
278 SdMmcIoProtocol to it.\r
279 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
280 of resources.\r
281 @retval EFI_ALREADY_STARTED The device was discovered before.\r
282 @retval Others Fail to discover the device.\r
283\r
284**/\r
285EFI_STATUS\r
286EFIAPI\r
287DiscoverSdDevice (\r
288 IN SD_DRIVER_PRIVATE_DATA *Private,\r
289 IN UINT8 Slot\r
290 )\r
291{\r
292 EFI_STATUS Status;\r
293 SD_DEVICE *Device;\r
294 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
295 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
296 EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;\r
297 EFI_HANDLE DeviceHandle;\r
298 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
299\r
300 Device = NULL;\r
301 DevicePath = NULL;\r
302 NewDevicePath = NULL;\r
303 RemainingDevicePath = NULL;\r
304 PassThru = Private->PassThru;\r
305\r
306 //\r
307 // Build Device Path\r
308 //\r
309 Status = PassThru->BuildDevicePath (\r
310 PassThru,\r
311 Slot,\r
312 &DevicePath\r
313 );\r
314 if (EFI_ERROR(Status)) {\r
315 return Status;\r
316 }\r
317\r
318 if (DevicePath->SubType != MSG_SD_DP) {\r
319 Status = EFI_UNSUPPORTED;\r
320 goto Error;\r
321 }\r
322\r
323 NewDevicePath = AppendDevicePathNode (\r
324 Private->ParentDevicePath,\r
325 DevicePath\r
326 );\r
327\r
328 if (NewDevicePath == NULL) {\r
329 Status = EFI_OUT_OF_RESOURCES;\r
330 goto Error;\r
331 }\r
332\r
333 DeviceHandle = NULL;\r
334 RemainingDevicePath = NewDevicePath;\r
335 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);\r
336 if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {\r
337 //\r
338 // The device has been started, directly return to fast boot.\r
339 //\r
340 Status = EFI_ALREADY_STARTED;\r
341 goto Error;\r
342 }\r
343\r
344 //\r
345 // Allocate buffer to store SD_DEVICE private data.\r
346 //\r
347 Device = AllocateCopyPool (sizeof (SD_DEVICE), &mSdDeviceTemplate);\r
348 if (Device == NULL) {\r
349 Status = EFI_OUT_OF_RESOURCES;\r
350 goto Error;\r
351 }\r
352\r
353 Device->DevicePath = NewDevicePath;\r
354 Device->Slot = Slot;\r
355 Device->Private = Private;\r
356 InitializeListHead (&Device->Queue);\r
357\r
358 //\r
359 // Expose user area in the Sd memory card to upper layer.\r
360 //\r
361 Status = DiscoverUserArea (Device);\r
362 if (EFI_ERROR(Status)) {\r
363 goto Error;\r
364 }\r
365\r
366 Device->ControllerNameTable = NULL;\r
367 AddUnicodeString2 (\r
368 "eng",\r
369 gSdDxeComponentName.SupportedLanguages,\r
370 &Device->ControllerNameTable,\r
371 Device->ModelName,\r
372 TRUE\r
373 );\r
374 AddUnicodeString2 (\r
375 "en",\r
376 gSdDxeComponentName.SupportedLanguages,\r
377 &Device->ControllerNameTable,\r
378 Device->ModelName,\r
379 FALSE\r
380 );\r
381\r
382 Status = gBS->InstallMultipleProtocolInterfaces (\r
383 &Device->Handle,\r
384 &gEfiDevicePathProtocolGuid,\r
385 Device->DevicePath,\r
386 &gEfiBlockIoProtocolGuid,\r
387 &Device->BlockIo,\r
388 &gEfiBlockIo2ProtocolGuid,\r
389 &Device->BlockIo2,\r
275d5136
FT
390 &gEfiEraseBlockProtocolGuid,\r
391 &Device->EraseBlock,\r
af6a6bf4
HW
392 &gEfiDiskInfoProtocolGuid,\r
393 &Device->DiskInfo,\r
48555339
FT
394 NULL\r
395 );\r
396\r
397 if (!EFI_ERROR (Status)) {\r
398 gBS->OpenProtocol (\r
399 Private->Controller,\r
400 &gEfiSdMmcPassThruProtocolGuid,\r
401 (VOID **) &(Private->PassThru),\r
402 Private->DriverBindingHandle,\r
403 Device->Handle,\r
404 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
405 );\r
406 }\r
407\r
408Error:\r
409 FreePool (DevicePath);\r
410\r
411 if (EFI_ERROR (Status) && (NewDevicePath != NULL)) {\r
412 FreePool (NewDevicePath);\r
413 }\r
414\r
415 if (EFI_ERROR (Status) && (Device != NULL)) {\r
416 FreePool (Device);\r
417 }\r
418\r
419 return Status;\r
420}\r
421\r
422/**\r
423 Tests to see if this driver supports a given controller. If a child device is provided,\r
424 it further tests to see if this driver supports creating a handle for the specified child device.\r
425\r
426 This function checks to see if the driver specified by This supports the device specified by\r
427 ControllerHandle. Drivers will typically use the device path attached to\r
428 ControllerHandle and/or the services from the bus I/O abstraction attached to\r
429 ControllerHandle to determine if the driver supports ControllerHandle. This function\r
430 may be called many times during platform initialization. In order to reduce boot times, the tests\r
431 performed by this function must be very small, and take as little time as possible to execute. This\r
432 function must not change the state of any hardware devices, and this function must be aware that the\r
433 device specified by ControllerHandle may already be managed by the same driver or a\r
434 different driver. This function must match its calls to AllocatePages() with FreePages(),\r
435 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
436 Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
437 already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
438 to guarantee the state of ControllerHandle is not modified by this function.\r
439\r
440 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
441 @param[in] ControllerHandle The handle of the controller to test. This handle\r
442 must support a protocol interface that supplies\r
443 an I/O abstraction to the driver.\r
444 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
445 parameter is ignored by device drivers, and is optional for bus\r
446 drivers. For bus drivers, if this parameter is not NULL, then\r
447 the bus driver must determine if the bus controller specified\r
448 by ControllerHandle and the child controller specified\r
449 by RemainingDevicePath are both supported by this\r
450 bus driver.\r
451\r
452 @retval EFI_SUCCESS The device specified by ControllerHandle and\r
453 RemainingDevicePath is supported by the driver specified by This.\r
454 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
455 RemainingDevicePath is already being managed by the driver\r
456 specified by This.\r
457 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
458 RemainingDevicePath is already being managed by a different\r
459 driver or an application that requires exclusive access.\r
460 Currently not implemented.\r
461 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
462 RemainingDevicePath is not supported by the driver specified by This.\r
463**/\r
464EFI_STATUS\r
465EFIAPI\r
466SdDxeDriverBindingSupported (\r
467 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
468 IN EFI_HANDLE Controller,\r
469 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
470 )\r
471{\r
472 EFI_STATUS Status;\r
473 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
474 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
475 UINT8 Slot;\r
476\r
477 //\r
478 // Test EFI_SD_MMC_PASS_THRU_PROTOCOL on the controller handle.\r
479 //\r
480 Status = gBS->OpenProtocol (\r
481 Controller,\r
482 &gEfiSdMmcPassThruProtocolGuid,\r
483 (VOID**) &PassThru,\r
484 This->DriverBindingHandle,\r
485 Controller,\r
486 EFI_OPEN_PROTOCOL_BY_DRIVER\r
487 );\r
488\r
489 if (Status == EFI_ALREADY_STARTED) {\r
490 return EFI_SUCCESS;\r
491 }\r
492\r
493 if (EFI_ERROR (Status)) {\r
494 return Status;\r
495 }\r
496\r
497 //\r
498 // Test RemainingDevicePath is valid or not.\r
499 //\r
500 if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {\r
501 Status = PassThru->GetSlotNumber (PassThru, RemainingDevicePath, &Slot);\r
502 if (EFI_ERROR (Status)) {\r
503 //\r
504 // Close the I/O Abstraction(s) used to perform the supported test\r
505 //\r
506 gBS->CloseProtocol (\r
507 Controller,\r
508 &gEfiSdMmcPassThruProtocolGuid,\r
509 This->DriverBindingHandle,\r
510 Controller\r
511 );\r
512 return Status;\r
513 }\r
514 }\r
515\r
516 //\r
517 // Close the I/O Abstraction(s) used to perform the supported test\r
518 //\r
519 gBS->CloseProtocol (\r
520 Controller,\r
521 &gEfiSdMmcPassThruProtocolGuid,\r
522 This->DriverBindingHandle,\r
523 Controller\r
524 );\r
525\r
526 //\r
527 // Open the EFI Device Path protocol needed to perform the supported test\r
528 //\r
529 Status = gBS->OpenProtocol (\r
530 Controller,\r
531 &gEfiDevicePathProtocolGuid,\r
532 (VOID **) &ParentDevicePath,\r
533 This->DriverBindingHandle,\r
534 Controller,\r
535 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
536 );\r
537 return Status;\r
538}\r
539\r
540/**\r
541 Starts a device controller or a bus controller.\r
542\r
543 The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
544 As a result, much of the error checking on the parameters to Start() has been moved into this\r
545 common boot service. It is legal to call Start() from other locations,\r
546 but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
547 1. ControllerHandle must be a valid EFI_HANDLE.\r
548 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
549 EFI_DEVICE_PATH_PROTOCOL.\r
550 3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
551 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
552\r
553 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
554 @param[in] ControllerHandle The handle of the controller to start. This handle\r
555 must support a protocol interface that supplies\r
556 an I/O abstraction to the driver.\r
557 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
558 parameter is ignored by device drivers, and is optional for bus\r
559 drivers. For a bus driver, if this parameter is NULL, then handles\r
560 for all the children of Controller are created by this driver.\r
561 If this parameter is not NULL and the first Device Path Node is\r
562 not the End of Device Path Node, then only the handle for the\r
563 child device specified by the first Device Path Node of\r
564 RemainingDevicePath is created by this driver.\r
565 If the first Device Path Node of RemainingDevicePath is\r
566 the End of Device Path Node, no child handle is created by this\r
567 driver.\r
568\r
569 @retval EFI_SUCCESS The device was started.\r
570 @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.\r
571 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
572 @retval Others The driver failded to start the device.\r
573\r
574**/\r
575EFI_STATUS\r
576EFIAPI\r
577SdDxeDriverBindingStart (\r
578 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
579 IN EFI_HANDLE Controller,\r
580 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
581 )\r
582{\r
583 EFI_STATUS Status;\r
584 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
585 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
586 SD_DRIVER_PRIVATE_DATA *Private;\r
587 UINT8 Slot;\r
588\r
589 Private = NULL;\r
590 PassThru = NULL;\r
591 Status = gBS->OpenProtocol (\r
592 Controller,\r
593 &gEfiSdMmcPassThruProtocolGuid,\r
594 (VOID **) &PassThru,\r
595 This->DriverBindingHandle,\r
596 Controller,\r
597 EFI_OPEN_PROTOCOL_BY_DRIVER\r
598 );\r
599 if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {\r
600 return Status;\r
601 }\r
602\r
603 //\r
604 // Check EFI_ALREADY_STARTED to reuse the original SD_DRIVER_PRIVATE_DATA.\r
605 //\r
606 if (Status != EFI_ALREADY_STARTED) {\r
607 Private = AllocateZeroPool (sizeof (SD_DRIVER_PRIVATE_DATA));\r
608 if (Private == NULL) {\r
609 Status = EFI_OUT_OF_RESOURCES;\r
610 goto Error;\r
611 }\r
612\r
613 Status = gBS->OpenProtocol (\r
614 Controller,\r
615 &gEfiDevicePathProtocolGuid,\r
616 (VOID **) &ParentDevicePath,\r
617 This->DriverBindingHandle,\r
618 Controller,\r
619 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
620 );\r
621 ASSERT_EFI_ERROR (Status);\r
622 Private->PassThru = PassThru;\r
623 Private->Controller = Controller;\r
624 Private->ParentDevicePath = ParentDevicePath;\r
625 Private->DriverBindingHandle = This->DriverBindingHandle;\r
626\r
627 Status = gBS->InstallProtocolInterface (\r
628 &Controller,\r
629 &gEfiCallerIdGuid,\r
630 EFI_NATIVE_INTERFACE,\r
631 Private\r
632 );\r
633 if (EFI_ERROR (Status)) {\r
634 goto Error;\r
635 }\r
636 } else {\r
637 Status = gBS->OpenProtocol (\r
638 Controller,\r
639 &gEfiCallerIdGuid,\r
640 (VOID **) &Private,\r
641 This->DriverBindingHandle,\r
642 Controller,\r
643 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
644 );\r
645 if (EFI_ERROR (Status)) {\r
646 goto Error;\r
647 }\r
648 }\r
649\r
650 if (RemainingDevicePath == NULL) {\r
651 Slot = 0xFF;\r
652 while (TRUE) {\r
653 Status = PassThru->GetNextSlot (PassThru, &Slot);\r
654 if (EFI_ERROR (Status)) {\r
655 //\r
656 // Cannot find more legal slots.\r
657 //\r
658 Status = EFI_SUCCESS;\r
659 break;\r
660 }\r
661\r
662 Status = DiscoverSdDevice (Private, Slot);\r
663 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
664 break;\r
665 }\r
666 }\r
667 } else if (!IsDevicePathEnd (RemainingDevicePath)) {\r
668 Status = PassThru->GetSlotNumber (PassThru, RemainingDevicePath, &Slot);\r
669 if (!EFI_ERROR (Status)) {\r
670 Status = DiscoverSdDevice (Private, Slot);\r
671 }\r
672 }\r
673\r
674Error:\r
675 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
676 gBS->CloseProtocol (\r
677 Controller,\r
678 &gEfiSdMmcPassThruProtocolGuid,\r
679 This->DriverBindingHandle,\r
680 Controller\r
681 );\r
682\r
683 if (Private != NULL) {\r
684 gBS->UninstallMultipleProtocolInterfaces (\r
685 Controller,\r
686 &gEfiCallerIdGuid,\r
687 Private,\r
688 NULL\r
689 );\r
690 FreePool (Private);\r
691 }\r
692 }\r
693 return Status;\r
694}\r
695\r
696/**\r
697 Stops a device controller or a bus controller.\r
698\r
699 The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
700 As a result, much of the error checking on the parameters to Stop() has been moved\r
701 into this common boot service. It is legal to call Stop() from other locations,\r
702 but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
703 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
704 same driver's Start() function.\r
705 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
706 EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
707 Start() function, and the Start() function must have called OpenProtocol() on\r
708 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
709\r
710 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
711 @param[in] ControllerHandle A handle to the device being stopped. The handle must\r
712 support a bus specific I/O protocol for the driver\r
713 to use to stop the device.\r
714 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.\r
715 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL\r
716 if NumberOfChildren is 0.\r
717\r
718 @retval EFI_SUCCESS The device was stopped.\r
719 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
720\r
721**/\r
722EFI_STATUS\r
723EFIAPI\r
724SdDxeDriverBindingStop (\r
725 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
726 IN EFI_HANDLE Controller,\r
727 IN UINTN NumberOfChildren,\r
728 IN EFI_HANDLE *ChildHandleBuffer\r
729 )\r
730{\r
731 EFI_STATUS Status;\r
732 BOOLEAN AllChildrenStopped;\r
733 UINTN Index;\r
734 SD_DRIVER_PRIVATE_DATA *Private;\r
735 SD_DEVICE *Device;\r
736 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
737 EFI_BLOCK_IO2_PROTOCOL *BlockIo2;\r
738 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
739 LIST_ENTRY *Link;\r
740 LIST_ENTRY *NextLink;\r
741 SD_REQUEST *Request;\r
742 EFI_TPL OldTpl;\r
743\r
744 if (NumberOfChildren == 0) {\r
745 Status = gBS->OpenProtocol (\r
746 Controller,\r
747 &gEfiCallerIdGuid,\r
748 (VOID **) &Private,\r
749 This->DriverBindingHandle,\r
750 Controller,\r
751 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
752 );\r
753 if (EFI_ERROR (Status)) {\r
754 return EFI_DEVICE_ERROR;\r
755 }\r
756\r
757 gBS->UninstallProtocolInterface (\r
758 Controller,\r
759 &gEfiCallerIdGuid,\r
760 Private\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 FreePool (Private);\r
770\r
771 return EFI_SUCCESS;\r
772 }\r
773\r
774 AllChildrenStopped = TRUE;\r
775\r
776 for (Index = 0; Index < NumberOfChildren; Index++) {\r
777 BlockIo = NULL;\r
778 BlockIo2 = NULL;\r
779 Status = gBS->OpenProtocol (\r
780 ChildHandleBuffer[Index],\r
781 &gEfiBlockIoProtocolGuid,\r
782 (VOID **) &BlockIo,\r
783 This->DriverBindingHandle,\r
784 Controller,\r
785 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
786 );\r
787 if (EFI_ERROR (Status)) {\r
788 Status = gBS->OpenProtocol (\r
789 ChildHandleBuffer[Index],\r
790 &gEfiBlockIo2ProtocolGuid,\r
791 (VOID **) &BlockIo2,\r
792 This->DriverBindingHandle,\r
793 Controller,\r
794 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
795 );\r
796 if (EFI_ERROR (Status)) {\r
797 AllChildrenStopped = FALSE;\r
798 continue;\r
799 }\r
800 }\r
801\r
802 if (BlockIo != NULL) {\r
803 Device = SD_DEVICE_DATA_FROM_BLKIO (BlockIo);\r
804 } else {\r
805 ASSERT (BlockIo2 != NULL);\r
806 Device = SD_DEVICE_DATA_FROM_BLKIO2 (BlockIo2);\r
807 }\r
808\r
809 //\r
810 // Free all on-going async tasks.\r
811 //\r
3b1d8241 812 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
48555339
FT
813 for (Link = GetFirstNode (&Device->Queue);\r
814 !IsNull (&Device->Queue, Link);\r
815 Link = NextLink) {\r
816 NextLink = GetNextNode (&Device->Queue, Link);\r
817 RemoveEntryList (Link);\r
818\r
819 Request = SD_REQUEST_FROM_LINK (Link);\r
820\r
821 gBS->CloseEvent (Request->Event);\r
822 Request->Token->TransactionStatus = EFI_ABORTED;\r
823\r
824 if (Request->IsEnd) {\r
825 gBS->SignalEvent (Request->Token->Event);\r
826 }\r
827\r
828 FreePool (Request);\r
829 }\r
830 gBS->RestoreTPL (OldTpl);\r
831\r
832 //\r
833 // Close the child handle\r
834 //\r
835 Status = gBS->CloseProtocol (\r
836 Controller,\r
837 &gEfiSdMmcPassThruProtocolGuid,\r
838 This->DriverBindingHandle,\r
839 ChildHandleBuffer[Index]\r
840 );\r
841\r
842 Status = gBS->UninstallMultipleProtocolInterfaces (\r
843 ChildHandleBuffer[Index],\r
844 &gEfiDevicePathProtocolGuid,\r
845 Device->DevicePath,\r
846 &gEfiBlockIoProtocolGuid,\r
847 &Device->BlockIo,\r
848 &gEfiBlockIo2ProtocolGuid,\r
849 &Device->BlockIo2,\r
275d5136
FT
850 &gEfiEraseBlockProtocolGuid,\r
851 &Device->EraseBlock,\r
af6a6bf4
HW
852 &gEfiDiskInfoProtocolGuid,\r
853 &Device->DiskInfo,\r
48555339
FT
854 NULL\r
855 );\r
856 if (EFI_ERROR (Status)) {\r
857 AllChildrenStopped = FALSE;\r
858 gBS->OpenProtocol (\r
859 Controller,\r
860 &gEfiSdMmcPassThruProtocolGuid,\r
861 (VOID **)&PassThru,\r
862 This->DriverBindingHandle,\r
863 ChildHandleBuffer[Index],\r
864 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
865 );\r
866 } else {\r
867 FreePool (Device->DevicePath);\r
868 FreeUnicodeStringTable (Device->ControllerNameTable);\r
869 FreePool (Device);\r
870 }\r
871 }\r
872\r
873 if (!AllChildrenStopped) {\r
874 return EFI_DEVICE_ERROR;\r
875 }\r
876\r
877 return EFI_SUCCESS;\r
878}\r
879\r
880/**\r
881 The user Entry Point for module SdDxe. The user code starts with this function.\r
882\r
883 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
884 @param[in] SystemTable A pointer to the EFI System Table.\r
885\r
886 @retval EFI_SUCCESS The entry point is executed successfully.\r
887 @retval other Some errors occur when executing this entry point.\r
888\r
889**/\r
890EFI_STATUS\r
891EFIAPI\r
892InitializeSdDxe (\r
893 IN EFI_HANDLE ImageHandle,\r
894 IN EFI_SYSTEM_TABLE *SystemTable\r
895 )\r
896{\r
897 EFI_STATUS Status;\r
898\r
899 //\r
900 // Install driver model protocol(s).\r
901 //\r
902 Status = EfiLibInstallDriverBindingComponentName2 (\r
903 ImageHandle,\r
904 SystemTable,\r
905 &gSdDxeDriverBinding,\r
906 ImageHandle,\r
907 &gSdDxeComponentName,\r
908 &gSdDxeComponentName2\r
909 );\r
910 ASSERT_EFI_ERROR (Status);\r
911\r
912 return Status;\r
913}\r
914\r