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