]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c
MdeModulePkg/SdMmc: Add EDKII SD/MMC stack
[mirror_edk2.git] / MdeModulePkg / Bus / Sd / SdDxe / SdBlockIo.c
1 /** @file
2 The helper functions for BlockIo and BlockIo2 protocol.
3
4 Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "SdDxe.h"
16
17 /**
18 Nonblocking I/O callback funtion when the event is signaled.
19
20 @param[in] Event The Event this notify function registered to.
21 @param[in] Context Pointer to the context data registered to the
22 Event.
23
24 **/
25 VOID
26 EFIAPI
27 AsyncIoCallback (
28 IN EFI_EVENT Event,
29 IN VOID *Context
30 )
31 {
32 SD_REQUEST *Request;
33
34 gBS->CloseEvent (Event);
35
36 Request = (SD_REQUEST *) Context;
37
38 DEBUG_CODE_BEGIN ();
39 DEBUG ((EFI_D_INFO, "Sd Async Request: CmdIndex[%d] Arg[%08x] %r\n",
40 Request->SdMmcCmdBlk.CommandIndex, Request->SdMmcCmdBlk.CommandArgument,
41 Request->Packet.TransactionStatus));
42 DEBUG_CODE_END ();
43
44 if (EFI_ERROR (Request->Packet.TransactionStatus)) {
45 Request->Token->TransactionStatus = Request->Packet.TransactionStatus;
46 }
47
48 RemoveEntryList (&Request->Link);
49
50 if (Request->IsEnd) {
51 gBS->SignalEvent (Request->Token->Event);
52 }
53
54 FreePool (Request);
55 }
56
57 /**
58 Send command SET_RELATIVE_ADDRESS to the device to set the device address.
59
60 @param[in] Device A pointer to the SD_DEVICE instance.
61 @param[out] Rca The relative device address to assign.
62
63 @retval EFI_SUCCESS The request is executed successfully.
64 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
65 @retval Others The request could not be executed successfully.
66
67 **/
68 EFI_STATUS
69 SdSetRca (
70 IN SD_DEVICE *Device,
71 OUT UINT16 *Rca
72 )
73 {
74 EFI_STATUS Status;
75 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
76 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
77 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
78 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
79
80 PassThru = Device->Private->PassThru;
81
82 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
83 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
84 ZeroMem (&Packet, sizeof (Packet));
85 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
86 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
87 Packet.Timeout = SD_GENERIC_TIMEOUT;
88
89 SdMmcCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR;
90 SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
91 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR6;
92
93 Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
94 if (!EFI_ERROR (Status)) {
95 DEBUG ((EFI_D_INFO, "Set RCA succeeds with Resp0 = 0x%x\n", SdMmcStatusBlk.Resp0));
96 *Rca = (UINT16)(SdMmcStatusBlk.Resp0 >> 16);
97 }
98
99 return Status;
100 }
101
102 /**
103 Send command SELECT to the device to select/deselect the device.
104
105 @param[in] Device A pointer to the SD_DEVICE instance.
106 @param[in] Rca The relative device address to use.
107
108 @retval EFI_SUCCESS The request is executed successfully.
109 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
110 @retval Others The request could not be executed successfully.
111
112 **/
113 EFI_STATUS
114 SdSelect (
115 IN SD_DEVICE *Device,
116 IN UINT16 Rca
117 )
118 {
119 EFI_STATUS Status;
120 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
121 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
122 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
123 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
124
125 PassThru = Device->Private->PassThru;
126
127 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
128 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
129 ZeroMem (&Packet, sizeof (Packet));
130 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
131 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
132 Packet.Timeout = SD_GENERIC_TIMEOUT;
133
134 SdMmcCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD;
135 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
136 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
137 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
138
139 Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
140
141 return Status;
142 }
143
144 /**
145 Send command SEND_STATUS to the device to get device status.
146
147 @param[in] Device A pointer to the SD_DEVICE instance.
148 @param[in] Rca The relative device address to use.
149 @param[out] DevStatus The buffer to store the device status.
150
151 @retval EFI_SUCCESS The request is executed successfully.
152 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
153 @retval Others The request could not be executed successfully.
154
155 **/
156 EFI_STATUS
157 SdSendStatus (
158 IN SD_DEVICE *Device,
159 IN UINT16 Rca,
160 OUT UINT32 *DevStatus
161 )
162 {
163 EFI_STATUS Status;
164 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
165 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
166 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
167 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
168
169 PassThru = Device->Private->PassThru;
170
171 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
172 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
173 ZeroMem (&Packet, sizeof (Packet));
174 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
175 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
176 Packet.Timeout = SD_GENERIC_TIMEOUT;
177
178 SdMmcCmdBlk.CommandIndex = SD_SEND_STATUS;
179 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
180 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
181 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
182
183 Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
184 if (!EFI_ERROR (Status)) {
185 CopyMem (DevStatus, &SdMmcStatusBlk.Resp0, sizeof (UINT32));
186 }
187 return Status;
188 }
189
190 /**
191 Send command SEND_CSD to the device to get the CSD register data.
192
193 @param[in] Device A pointer to the SD_DEVICE instance.
194 @param[in] Rca The relative device address to use.
195 @param[out] Csd The buffer to store the SD_CSD register data.
196
197 @retval EFI_SUCCESS The request is executed successfully.
198 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
199 @retval Others The request could not be executed successfully.
200
201 **/
202 EFI_STATUS
203 SdGetCsd (
204 IN SD_DEVICE *Device,
205 IN UINT16 Rca,
206 OUT SD_CSD *Csd
207 )
208 {
209 EFI_STATUS Status;
210 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
211 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
212 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
213 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
214
215 PassThru = Device->Private->PassThru;
216
217 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
218 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
219 ZeroMem (&Packet, sizeof (Packet));
220 ZeroMem (Csd, sizeof (SD_CSD));
221
222 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
223 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
224 Packet.Timeout = SD_GENERIC_TIMEOUT;
225
226 SdMmcCmdBlk.CommandIndex = SD_SEND_CSD;
227 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
228 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
229 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
230
231 Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
232
233 if (!EFI_ERROR (Status)) {
234 //
235 // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
236 //
237 CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CSD) - 1);
238 }
239
240 return Status;
241 }
242
243 /**
244 Send command SEND_CID to the device to get the CID register data.
245
246 @param[in] Device A pointer to the SD_DEVICE instance.
247 @param[in] Rca The relative device address to use.
248 @param[out] Cid The buffer to store the SD_CID register data.
249
250 @retval EFI_SUCCESS The request is executed successfully.
251 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
252 @retval Others The request could not be executed successfully.
253
254 **/
255 EFI_STATUS
256 SdGetCid (
257 IN SD_DEVICE *Device,
258 IN UINT16 Rca,
259 OUT SD_CID *Cid
260 )
261 {
262 EFI_STATUS Status;
263 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
264 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
265 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
266 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
267
268 PassThru = Device->Private->PassThru;
269
270 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
271 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
272 ZeroMem (&Packet, sizeof (Packet));
273 ZeroMem (Cid, sizeof (SD_CID));
274
275 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
276 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
277 Packet.Timeout = SD_GENERIC_TIMEOUT;
278
279 SdMmcCmdBlk.CommandIndex = SD_SEND_CID;
280 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
281 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
282 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
283
284 Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
285
286 if (!EFI_ERROR (Status)) {
287 //
288 // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
289 //
290 CopyMem (((UINT8*)Cid) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CID) - 1);
291 }
292
293 return Status;
294 }
295
296 /**
297 Read/write single block through sync or async I/O request.
298
299 @param[in] Device A pointer to the SD_DEVICE instance.
300 @param[in] Lba The starting logical block address to be read/written.
301 The caller is responsible for reading/writing to only
302 legitimate locations.
303 @param[in] Buffer A pointer to the destination/source buffer for the data.
304 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
305 @param[in] IsRead Indicates it is a read or write operation.
306 @param[in] Token A pointer to the token associated with the transaction.
307 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
308 This parameter is only meaningful in async I/O request.
309
310 @retval EFI_SUCCESS The request is executed successfully.
311 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
312 @retval Others The request could not be executed successfully.
313
314 **/
315 EFI_STATUS
316 SdRwSingleBlock (
317 IN SD_DEVICE *Device,
318 IN EFI_LBA Lba,
319 IN VOID *Buffer,
320 IN UINTN BufferSize,
321 IN BOOLEAN IsRead,
322 IN EFI_BLOCK_IO2_TOKEN *Token,
323 IN BOOLEAN IsEnd
324 )
325 {
326 EFI_STATUS Status;
327 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
328 SD_REQUEST *RwSingleBlkReq;
329 EFI_TPL OldTpl;
330
331 RwSingleBlkReq = NULL;
332 PassThru = Device->Private->PassThru;
333
334 RwSingleBlkReq = AllocateZeroPool (sizeof (SD_REQUEST));
335 if (RwSingleBlkReq == NULL) {
336 Status = EFI_OUT_OF_RESOURCES;
337 goto Error;
338 }
339
340 RwSingleBlkReq->Signature = SD_REQUEST_SIGNATURE;
341 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
342 InsertTailList (&Device->Queue, &RwSingleBlkReq->Link);
343 gBS->RestoreTPL (OldTpl);
344 RwSingleBlkReq->Packet.SdMmcCmdBlk = &RwSingleBlkReq->SdMmcCmdBlk;
345 RwSingleBlkReq->Packet.SdMmcStatusBlk = &RwSingleBlkReq->SdMmcStatusBlk;
346 //
347 // Calculate timeout value through the below formula.
348 // Timeout = (transfer size) / (2MB/s).
349 // Taking 2MB/s as divisor as it's the lowest transfer speed
350 // above class 2.
351 // Refer to SD Physical Layer Simplified spec section 3.4 for details.
352 //
353 RwSingleBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;
354
355 if (IsRead) {
356 RwSingleBlkReq->Packet.InDataBuffer = Buffer;
357 RwSingleBlkReq->Packet.InTransferLength = (UINT32)BufferSize;
358
359 RwSingleBlkReq->SdMmcCmdBlk.CommandIndex = SD_READ_SINGLE_BLOCK;
360 RwSingleBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
361 RwSingleBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
362 } else {
363 RwSingleBlkReq->Packet.OutDataBuffer = Buffer;
364 RwSingleBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;
365
366 RwSingleBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_SINGLE_BLOCK;
367 RwSingleBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
368 RwSingleBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
369 }
370
371 if (Device->SectorAddressing) {
372 RwSingleBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;
373 } else {
374 RwSingleBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->BlockMedia.BlockSize);
375 }
376
377 RwSingleBlkReq->IsEnd = IsEnd;
378 RwSingleBlkReq->Token = Token;
379
380 if ((Token != NULL) && (Token->Event != NULL)) {
381 Status = gBS->CreateEvent (
382 EVT_NOTIFY_SIGNAL,
383 TPL_CALLBACK,
384 AsyncIoCallback,
385 RwSingleBlkReq,
386 &RwSingleBlkReq->Event
387 );
388 if (EFI_ERROR (Status)) {
389 goto Error;
390 }
391 } else {
392 RwSingleBlkReq->Event = NULL;
393 }
394
395 Status = PassThru->PassThru (PassThru, Device->Slot, &RwSingleBlkReq->Packet, RwSingleBlkReq->Event);
396
397 Error:
398 if ((Token != NULL) && (Token->Event != NULL)) {
399 //
400 // For asynchronous operation, only free request and event in error case.
401 // The request and event will be freed in asynchronous callback for success case.
402 //
403 if (EFI_ERROR (Status) && (RwSingleBlkReq != NULL)) {
404 RemoveEntryList (&RwSingleBlkReq->Link);
405 if (RwSingleBlkReq->Event != NULL) {
406 gBS->CloseEvent (RwSingleBlkReq->Event);
407 }
408 FreePool (RwSingleBlkReq);
409 }
410 } else {
411 //
412 // For synchronous operation, free request whatever the execution result is.
413 //
414 if (RwSingleBlkReq != NULL) {
415 RemoveEntryList (&RwSingleBlkReq->Link);
416 FreePool (RwSingleBlkReq);
417 }
418 }
419
420 return Status;
421 }
422
423 /**
424 Read/write multiple blocks through sync or async I/O request.
425
426 @param[in] Device A pointer to the SD_DEVICE instance.
427 @param[in] Lba The starting logical block address to be read/written.
428 The caller is responsible for reading/writing to only
429 legitimate locations.
430 @param[in] Buffer A pointer to the destination/source buffer for the data.
431 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
432 @param[in] IsRead Indicates it is a read or write operation.
433 @param[in] Token A pointer to the token associated with the transaction.
434 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
435 This parameter is only meaningful in async I/O request.
436
437 @retval EFI_SUCCESS The request is executed successfully.
438 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
439 @retval Others The request could not be executed successfully.
440
441 **/
442 EFI_STATUS
443 SdRwMultiBlocks (
444 IN SD_DEVICE *Device,
445 IN EFI_LBA Lba,
446 IN VOID *Buffer,
447 IN UINTN BufferSize,
448 IN BOOLEAN IsRead,
449 IN EFI_BLOCK_IO2_TOKEN *Token,
450 IN BOOLEAN IsEnd
451 )
452 {
453 EFI_STATUS Status;
454 SD_REQUEST *RwMultiBlkReq;
455 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
456 EFI_TPL OldTpl;
457
458 RwMultiBlkReq = NULL;
459
460 PassThru = Device->Private->PassThru;
461
462 RwMultiBlkReq = AllocateZeroPool (sizeof (SD_REQUEST));
463 if (RwMultiBlkReq == NULL) {
464 Status = EFI_OUT_OF_RESOURCES;
465 goto Error;
466 }
467
468 RwMultiBlkReq->Signature = SD_REQUEST_SIGNATURE;
469 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
470 InsertTailList (&Device->Queue, &RwMultiBlkReq->Link);
471 gBS->RestoreTPL (OldTpl);
472 RwMultiBlkReq->Packet.SdMmcCmdBlk = &RwMultiBlkReq->SdMmcCmdBlk;
473 RwMultiBlkReq->Packet.SdMmcStatusBlk = &RwMultiBlkReq->SdMmcStatusBlk;
474 //
475 // Calculate timeout value through the below formula.
476 // Timeout = (transfer size) / (2MB/s).
477 // Taking 2MB/s as divisor as it's the lowest transfer speed
478 // above class 2.
479 // Refer to SD Physical Layer Simplified spec section 3.4 for details.
480 //
481 RwMultiBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;
482
483 if (IsRead) {
484 RwMultiBlkReq->Packet.InDataBuffer = Buffer;
485 RwMultiBlkReq->Packet.InTransferLength = (UINT32)BufferSize;
486
487 RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_READ_MULTIPLE_BLOCK;
488 RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
489 RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
490 } else {
491 RwMultiBlkReq->Packet.OutDataBuffer = Buffer;
492 RwMultiBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;
493
494 RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_MULTIPLE_BLOCK;
495 RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
496 RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
497 }
498
499 if (Device->SectorAddressing) {
500 RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;
501 } else {
502 RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->BlockMedia.BlockSize);
503 }
504
505 RwMultiBlkReq->IsEnd = IsEnd;
506 RwMultiBlkReq->Token = Token;
507
508 if ((Token != NULL) && (Token->Event != NULL)) {
509 Status = gBS->CreateEvent (
510 EVT_NOTIFY_SIGNAL,
511 TPL_CALLBACK,
512 AsyncIoCallback,
513 RwMultiBlkReq,
514 &RwMultiBlkReq->Event
515 );
516 if (EFI_ERROR (Status)) {
517 goto Error;
518 }
519 } else {
520 RwMultiBlkReq->Event = NULL;
521 }
522
523 Status = PassThru->PassThru (PassThru, Device->Slot, &RwMultiBlkReq->Packet, RwMultiBlkReq->Event);
524
525 Error:
526 if ((Token != NULL) && (Token->Event != NULL)) {
527 //
528 // For asynchronous operation, only free request and event in error case.
529 // The request and event will be freed in asynchronous callback for success case.
530 //
531 if (EFI_ERROR (Status) && (RwMultiBlkReq != NULL)) {
532 RemoveEntryList (&RwMultiBlkReq->Link);
533 if (RwMultiBlkReq->Event != NULL) {
534 gBS->CloseEvent (RwMultiBlkReq->Event);
535 }
536 FreePool (RwMultiBlkReq);
537 }
538 } else {
539 //
540 // For synchronous operation, free request whatever the execution result is.
541 //
542 if (RwMultiBlkReq != NULL) {
543 RemoveEntryList (&RwMultiBlkReq->Link);
544 FreePool (RwMultiBlkReq);
545 }
546 }
547
548 return Status;
549 }
550
551 /**
552 This function transfers data from/to the sd memory card device.
553
554 @param[in] Device A pointer to the SD_DEVICE instance.
555 @param[in] MediaId The media ID that the read/write request is for.
556 @param[in] Lba The starting logical block address to be read/written.
557 The caller is responsible for reading/writing to only
558 legitimate locations.
559 @param[in, out] Buffer A pointer to the destination/source buffer for the data.
560 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
561 @param[in] IsRead Indicates it is a read or write operation.
562 @param[in, out] Token A pointer to the token associated with the transaction.
563
564 @retval EFI_SUCCESS The data was read/written correctly to the device.
565 @retval EFI_WRITE_PROTECTED The device can not be read/written to.
566 @retval EFI_DEVICE_ERROR The device reported an error while performing the read/write.
567 @retval EFI_NO_MEDIA There is no media in the device.
568 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
569 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
570 @retval EFI_INVALID_PARAMETER The read/write request contains LBAs that are not valid,
571 or the buffer is not on proper alignment.
572
573 **/
574 EFI_STATUS
575 SdReadWrite (
576 IN SD_DEVICE *Device,
577 IN UINT32 MediaId,
578 IN EFI_LBA Lba,
579 IN OUT VOID *Buffer,
580 IN UINTN BufferSize,
581 IN BOOLEAN IsRead,
582 IN OUT EFI_BLOCK_IO2_TOKEN *Token
583 )
584 {
585 EFI_STATUS Status;
586 EFI_BLOCK_IO_MEDIA *Media;
587 UINTN BlockSize;
588 UINTN BlockNum;
589 UINTN IoAlign;
590 UINTN Remaining;
591 UINT32 MaxBlock;
592 BOOLEAN LastRw;
593
594 Status = EFI_SUCCESS;
595 Media = &Device->BlockMedia;
596 LastRw = FALSE;
597
598 if (MediaId != Media->MediaId) {
599 return EFI_MEDIA_CHANGED;
600 }
601
602 if (!IsRead && Media->ReadOnly) {
603 return EFI_WRITE_PROTECTED;
604 }
605
606 //
607 // Check parameters.
608 //
609 if (Buffer == NULL) {
610 return EFI_INVALID_PARAMETER;
611 }
612
613 if (BufferSize == 0) {
614 if ((Token != NULL) && (Token->Event != NULL)) {
615 Token->TransactionStatus = EFI_SUCCESS;
616 gBS->SignalEvent (Token->Event);
617 }
618 return EFI_SUCCESS;
619 }
620
621 BlockSize = Media->BlockSize;
622 if ((BufferSize % BlockSize) != 0) {
623 return EFI_BAD_BUFFER_SIZE;
624 }
625
626 BlockNum = BufferSize / BlockSize;
627 if ((Lba + BlockNum - 1) > Media->LastBlock) {
628 return EFI_INVALID_PARAMETER;
629 }
630
631 IoAlign = Media->IoAlign;
632 if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {
633 return EFI_INVALID_PARAMETER;
634 }
635
636 if ((Token != NULL) && (Token->Event != NULL)) {
637 Token->TransactionStatus = EFI_SUCCESS;
638 }
639
640 //
641 // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
642 //
643 Remaining = BlockNum;
644 MaxBlock = 0xFFFF;
645
646 while (Remaining > 0) {
647 if (Remaining <= MaxBlock) {
648 BlockNum = Remaining;
649 LastRw = TRUE;
650 } else {
651 BlockNum = MaxBlock;
652 }
653
654 BufferSize = BlockNum * BlockSize;
655 if (BlockNum == 1) {
656 Status = SdRwSingleBlock (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);
657 } else {
658 Status = SdRwMultiBlocks (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);
659 }
660 if (EFI_ERROR (Status)) {
661 return Status;
662 }
663 DEBUG ((EFI_D_INFO, "Sd%a(): Lba 0x%x BlkNo 0x%x Event %p with %r\n", IsRead ? "Read" : "Write", Lba, BlockNum, Token->Event, Status));
664
665 Lba += BlockNum;
666 Buffer = (UINT8*)Buffer + BufferSize;
667 Remaining -= BlockNum;
668 }
669
670 return Status;
671 }
672
673 /**
674 Reset the Block Device.
675
676 @param This Indicates a pointer to the calling context.
677 @param ExtendedVerification Driver may perform diagnostics on reset.
678
679 @retval EFI_SUCCESS The device was reset.
680 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
681 not be reset.
682
683 **/
684 EFI_STATUS
685 EFIAPI
686 SdReset (
687 IN EFI_BLOCK_IO_PROTOCOL *This,
688 IN BOOLEAN ExtendedVerification
689 )
690 {
691 EFI_STATUS Status;
692 SD_DEVICE *Device;
693 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
694
695 Device = SD_DEVICE_DATA_FROM_BLKIO (This);
696
697 PassThru = Device->Private->PassThru;
698 Status = PassThru->ResetDevice (PassThru, Device->Slot);
699 if (EFI_ERROR (Status)) {
700 Status = EFI_DEVICE_ERROR;
701 }
702
703 return Status;
704 }
705
706 /**
707 Read BufferSize bytes from Lba into Buffer.
708
709 @param This Indicates a pointer to the calling context.
710 @param MediaId Id of the media, changes every time the media is replaced.
711 @param Lba The starting Logical Block Address to read from
712 @param BufferSize Size of Buffer, must be a multiple of device block size.
713 @param Buffer A pointer to the destination buffer for the data. The caller is
714 responsible for either having implicit or explicit ownership of the buffer.
715
716 @retval EFI_SUCCESS The data was read correctly from the device.
717 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
718 @retval EFI_NO_MEDIA There is no media in the device.
719 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
720 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
721 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
722 or the buffer is not on proper alignment.
723
724 **/
725 EFI_STATUS
726 EFIAPI
727 SdReadBlocks (
728 IN EFI_BLOCK_IO_PROTOCOL *This,
729 IN UINT32 MediaId,
730 IN EFI_LBA Lba,
731 IN UINTN BufferSize,
732 OUT VOID *Buffer
733 )
734 {
735 EFI_STATUS Status;
736 SD_DEVICE *Device;
737
738 Device = SD_DEVICE_DATA_FROM_BLKIO (This);
739
740 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, NULL);
741 return Status;
742 }
743
744 /**
745 Write BufferSize bytes from Lba into Buffer.
746
747 @param This Indicates a pointer to the calling context.
748 @param MediaId The media ID that the write request is for.
749 @param Lba The starting logical block address to be written. The caller is
750 responsible for writing to only legitimate locations.
751 @param BufferSize Size of Buffer, must be a multiple of device block size.
752 @param Buffer A pointer to the source buffer for the data.
753
754 @retval EFI_SUCCESS The data was written correctly to the device.
755 @retval EFI_WRITE_PROTECTED The device can not be written to.
756 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
757 @retval EFI_NO_MEDIA There is no media in the device.
758 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
759 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
760 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
761 or the buffer is not on proper alignment.
762
763 **/
764 EFI_STATUS
765 EFIAPI
766 SdWriteBlocks (
767 IN EFI_BLOCK_IO_PROTOCOL *This,
768 IN UINT32 MediaId,
769 IN EFI_LBA Lba,
770 IN UINTN BufferSize,
771 IN VOID *Buffer
772 )
773 {
774 EFI_STATUS Status;
775 SD_DEVICE *Device;
776
777 Device = SD_DEVICE_DATA_FROM_BLKIO (This);
778
779 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, NULL);
780 return Status;
781 }
782
783 /**
784 Flush the Block Device.
785
786 @param This Indicates a pointer to the calling context.
787
788 @retval EFI_SUCCESS All outstanding data was written to the device
789 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
790 @retval EFI_NO_MEDIA There is no media in the device.
791
792 **/
793 EFI_STATUS
794 EFIAPI
795 SdFlushBlocks (
796 IN EFI_BLOCK_IO_PROTOCOL *This
797 )
798 {
799 //
800 // return directly
801 //
802 return EFI_SUCCESS;
803 }
804
805 /**
806 Reset the Block Device.
807
808 @param[in] This Indicates a pointer to the calling context.
809 @param[in] ExtendedVerification Driver may perform diagnostics on reset.
810
811 @retval EFI_SUCCESS The device was reset.
812 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
813 not be reset.
814
815 **/
816 EFI_STATUS
817 EFIAPI
818 SdResetEx (
819 IN EFI_BLOCK_IO2_PROTOCOL *This,
820 IN BOOLEAN ExtendedVerification
821 )
822 {
823 SD_DEVICE *Device;
824 LIST_ENTRY *Link;
825 LIST_ENTRY *NextLink;
826 SD_REQUEST *Request;
827 EFI_TPL OldTpl;
828
829 Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
830
831 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
832 for (Link = GetFirstNode (&Device->Queue);
833 !IsNull (&Device->Queue, Link);
834 Link = NextLink) {
835 NextLink = GetNextNode (&Device->Queue, Link);
836 RemoveEntryList (Link);
837
838 Request = SD_REQUEST_FROM_LINK (Link);
839
840 gBS->CloseEvent (Request->Event);
841 Request->Token->TransactionStatus = EFI_ABORTED;
842
843 if (Request->IsEnd) {
844 gBS->SignalEvent (Request->Token->Event);
845 }
846
847 FreePool (Request);
848 }
849 gBS->RestoreTPL (OldTpl);
850
851 return EFI_SUCCESS;
852 }
853
854 /**
855 Read BufferSize bytes from Lba into Buffer.
856
857 @param[in] This Indicates a pointer to the calling context.
858 @param[in] MediaId Id of the media, changes every time the media is replaced.
859 @param[in] Lba The starting Logical Block Address to read from.
860 @param[in, out] Token A pointer to the token associated with the transaction.
861 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
862 @param[out] Buffer A pointer to the destination buffer for the data. The caller is
863 responsible for either having implicit or explicit ownership of the buffer.
864
865 @retval EFI_SUCCESS The read request was queued if Event is not NULL.
866 The data was read correctly from the device if
867 the Event is NULL.
868 @retval EFI_DEVICE_ERROR The device reported an error while performing
869 the read.
870 @retval EFI_NO_MEDIA There is no media in the device.
871 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
872 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
873 intrinsic block size of the device.
874 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
875 or the buffer is not on proper alignment.
876 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
877 of resources.
878
879 **/
880 EFI_STATUS
881 EFIAPI
882 SdReadBlocksEx (
883 IN EFI_BLOCK_IO2_PROTOCOL *This,
884 IN UINT32 MediaId,
885 IN EFI_LBA Lba,
886 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
887 IN UINTN BufferSize,
888 OUT VOID *Buffer
889 )
890 {
891 EFI_STATUS Status;
892 SD_DEVICE *Device;
893
894 Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
895
896 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, Token);
897 return Status;
898 }
899
900 /**
901 Write BufferSize bytes from Lba into Buffer.
902
903 @param[in] This Indicates a pointer to the calling context.
904 @param[in] MediaId The media ID that the write request is for.
905 @param[in] Lba The starting logical block address to be written. The
906 caller is responsible for writing to only legitimate
907 locations.
908 @param[in, out] Token A pointer to the token associated with the transaction.
909 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
910 @param[in] Buffer A pointer to the source buffer for the data.
911
912 @retval EFI_SUCCESS The data was written correctly to the device.
913 @retval EFI_WRITE_PROTECTED The device can not be written to.
914 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
915 @retval EFI_NO_MEDIA There is no media in the device.
916 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
917 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
918 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
919 or the buffer is not on proper alignment.
920
921 **/
922 EFI_STATUS
923 EFIAPI
924 SdWriteBlocksEx (
925 IN EFI_BLOCK_IO2_PROTOCOL *This,
926 IN UINT32 MediaId,
927 IN EFI_LBA Lba,
928 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
929 IN UINTN BufferSize,
930 IN VOID *Buffer
931 )
932 {
933 EFI_STATUS Status;
934 SD_DEVICE *Device;
935
936 Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
937
938 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, Token);
939 return Status;
940 }
941
942 /**
943 Flush the Block Device.
944
945 @param[in] This Indicates a pointer to the calling context.
946 @param[in, out] Token A pointer to the token associated with the transaction.
947
948 @retval EFI_SUCCESS All outstanding data was written to the device
949 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
950 @retval EFI_NO_MEDIA There is no media in the device.
951
952 **/
953 EFI_STATUS
954 EFIAPI
955 SdFlushBlocksEx (
956 IN EFI_BLOCK_IO2_PROTOCOL *This,
957 IN OUT EFI_BLOCK_IO2_TOKEN *Token
958 )
959 {
960 //
961 // Signal event and return directly.
962 //
963 if (Token != NULL && Token->Event != NULL) {
964 Token->TransactionStatus = EFI_SUCCESS;
965 gBS->SignalEvent (Token->Event);
966 }
967
968 return EFI_SUCCESS;
969 }
970
971