• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2 
3 Block I/O protocol for MMC/SD device
4 
5 Copyright (c) 2013-2015 Intel Corporation.
6 
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution.  The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11 
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 
15 **/
16 
17 #include "SDMediaDevice.h"
18 
19 /**
20   Implements EFI_BLOCK_IO_PROTOCOL.Reset() function.
21 
22   @param  This                   The EFI_BLOCK_IO_PROTOCOL instance.
23   @param  ExtendedVerification   Indicates that the driver may perform a more exhaustive.
24                                  verification operation of the device during reset.
25                                  (This parameter is ingored in this driver.)
26 
27   @retval EFI_SUCCESS                Success
28 **/
29 EFI_STATUS
30 EFIAPI
MMCSDBlockReset(IN EFI_BLOCK_IO_PROTOCOL * This,IN BOOLEAN ExtendedVerification)31 MMCSDBlockReset (
32   IN  EFI_BLOCK_IO_PROTOCOL   *This,
33   IN  BOOLEAN                 ExtendedVerification
34   )
35 {
36   CARD_DATA                  *CardData;
37   EFI_SD_HOST_IO_PROTOCOL    *SDHostIo;
38 
39   CardData  = CARD_DATA_FROM_THIS(This);
40   SDHostIo = CardData->SDHostIo;
41 
42   return SDHostIo->ResetSDHost (SDHostIo, Reset_DAT_CMD);
43  }
44 
45 /**
46   Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function.
47 
48   @param  This                   The EFI_BLOCK_IO_PROTOCOL instance.
49   @param  MediaId                The media id that the write request is for.
50   @param  LBA                    The starting logical block address to read from on the device.
51                                  The caller is responsible for writing to only legitimate locations.
52   @param  BufferSize             The size of the Buffer in bytes. This must be a multiple of the
53                                  intrinsic block size of the device.
54   @param  Buffer                 A pointer to the destination buffer for the data. The caller
55                                  is responsible for either having implicit or explicit ownership
56                                  of the buffer.
57 
58   @retval EFI_SUCCESS                Success
59   @retval EFI_DEVICE_ERROR           Hardware Error
60   @retval EFI_INVALID_PARAMETER      Parameter is error
61   @retval EFI_NO_MEDIA               No media
62   @retval EFI_MEDIA_CHANGED          Media Change
63   @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
64 **/
65 EFI_STATUS
66 EFIAPI
MMCSDBlockReadBlocks(IN EFI_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA LBA,IN UINTN BufferSize,OUT VOID * Buffer)67 MMCSDBlockReadBlocks (
68   IN  EFI_BLOCK_IO_PROTOCOL   *This,
69   IN  UINT32                  MediaId,
70   IN  EFI_LBA                 LBA,
71   IN  UINTN                   BufferSize,
72   OUT VOID                    *Buffer
73   )
74 {
75   EFI_STATUS                  Status;
76   UINT32                      Address;
77   CARD_DATA                   *CardData;
78   EFI_SD_HOST_IO_PROTOCOL     *SDHostIo;
79   UINT32                      RemainingLength;
80   UINT32                      TransferLength;
81   UINT8                       *BufferPointer;
82   BOOLEAN                     SectorAddressing;
83   UINTN                       TotalBlock;
84 
85   DEBUG((EFI_D_INFO, "Read(LBA=%08lx, Buffer=%08x, Size=%08x)\n", LBA, Buffer, BufferSize));
86   Status   = EFI_SUCCESS;
87   CardData  = CARD_DATA_FROM_THIS(This);
88   SDHostIo = CardData->SDHostIo;
89   if (MediaId != CardData->BlockIoMedia.MediaId) {
90     return EFI_MEDIA_CHANGED;
91   }
92 
93   if (ModU64x32 (BufferSize,CardData->BlockIoMedia.BlockSize) != 0) {
94     return EFI_BAD_BUFFER_SIZE;
95   }
96   if ((CardData->CardType == SDMemoryCard2High) || (CardData->CardType == MMCCardHighCap)) {
97     SectorAddressing = TRUE;
98   } else {
99     SectorAddressing = FALSE;
100   }
101   if (SectorAddressing) {
102     //
103     //Block Address
104     //
105     Address = (UINT32)DivU64x32 (MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize), 512);
106   } else {
107     //
108     //Byte Address
109     //
110     Address  = (UINT32)MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize);
111   }
112   TotalBlock = (UINTN) DivU64x32 (BufferSize, CardData->BlockIoMedia.BlockSize);
113   if (LBA + TotalBlock > CardData->BlockIoMedia.LastBlock + 1) {
114     return EFI_INVALID_PARAMETER;
115   }
116 
117 
118   if (!Buffer) {
119     Status = EFI_INVALID_PARAMETER;
120     DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks:Invalid parameter \r\n"));
121     goto Done;
122   }
123 
124   if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
125     Status = EFI_BAD_BUFFER_SIZE;
126     DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: Bad buffer size \r\n"));
127     goto Done;
128   }
129 
130   if (BufferSize == 0) {
131     Status = EFI_SUCCESS;
132     goto Done;
133   }
134 
135 
136 
137 
138     BufferPointer   = Buffer;
139     RemainingLength = (UINT32)BufferSize;
140 
141     while (RemainingLength > 0) {
142     if ((BufferSize > CardData->BlockIoMedia.BlockSize)) {
143       if (RemainingLength > SDHostIo->HostCapability.BoundarySize) {
144         TransferLength = SDHostIo->HostCapability.BoundarySize;
145       } else {
146         TransferLength = RemainingLength;
147       }
148 
149       if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {
150         if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3))) {
151       Status = SendCommand (
152                      CardData,
153                      SET_BLOCKLEN,
154                      CardData->BlockIoMedia.BlockSize,
155                      NoData,
156                      NULL,
157                      0,
158                      ResponseR1,
159                      TIMEOUT_COMMAND,
160                      (UINT32*)&(CardData->CardStatus)
161                      );
162           if (EFI_ERROR (Status)) {
163             break;
164           }
165         }
166         Status = SendCommand (
167                    CardData,
168                    SET_BLOCK_COUNT,
169                    TransferLength / CardData->BlockIoMedia.BlockSize,
170                    NoData,
171                    NULL,
172                    0,
173                    ResponseR1,
174                    TIMEOUT_COMMAND,
175                    (UINT32*)&(CardData->CardStatus)
176                    );
177         if (EFI_ERROR (Status)) {
178           break;
179         }
180       }
181       Status = SendCommand (
182                  CardData,
183                  READ_MULTIPLE_BLOCK,
184                  Address,
185                  InData,
186                  CardData->AlignedBuffer,
187                  TransferLength,
188                  ResponseR1,
189                  TIMEOUT_DATA,
190                  (UINT32*)&(CardData->CardStatus)
191                  );
192 
193       if (EFI_ERROR (Status)) {
194         DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_MULTIPLE_BLOCK -> Fail\n"));
195         break;
196       }
197     } else {
198       if (RemainingLength > CardData->BlockIoMedia.BlockSize) {
199         TransferLength = CardData->BlockIoMedia.BlockSize;
200       } else {
201         TransferLength = RemainingLength;
202       }
203 
204       Status = SendCommand (
205                  CardData,
206                  READ_SINGLE_BLOCK,
207                  Address,
208                  InData,
209                  CardData->AlignedBuffer,
210                  (UINT32)TransferLength,
211                  ResponseR1,
212                  TIMEOUT_DATA,
213                  (UINT32*)&(CardData->CardStatus)
214                  );
215       if (EFI_ERROR (Status)) {
216         DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_SINGLE_BLOCK -> Fail\n"));
217         break;
218       }
219     }
220       CopyMem (BufferPointer, CardData->AlignedBuffer, TransferLength);
221 
222     if (SectorAddressing) {
223         //
224         //Block Address
225         //
226         Address += TransferLength / 512;
227       } else {
228         //
229         //Byte Address
230         //
231         Address += TransferLength;
232       }
233       BufferPointer   += TransferLength;
234       RemainingLength -= TransferLength;
235    }
236 
237 
238   if (EFI_ERROR (Status)) {
239     if ((CardData->CardType == SDMemoryCard) ||
240         (CardData->CardType == SDMemoryCard2)||
241         (CardData->CardType == SDMemoryCard2High)) {
242          SendCommand (
243            CardData,
244            STOP_TRANSMISSION,
245            0,
246            NoData,
247            NULL,
248            0,
249            ResponseR1b,
250            TIMEOUT_COMMAND,
251            (UINT32*)&(CardData->CardStatus)
252            );
253     } else {
254        SendCommand (
255          CardData,
256          STOP_TRANSMISSION,
257          0,
258          NoData,
259          NULL,
260          0,
261          ResponseR1,
262          TIMEOUT_COMMAND,
263          (UINT32*)&(CardData->CardStatus)
264          );
265     }
266 
267   }
268 
269 
270 Done:
271   DEBUG((EFI_D_INFO, "MMCSDBlockReadBlocks: Status = %r\n", Status));
272   return Status;
273 }
274 
275 /**
276   Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function.
277 
278   @param  This                   The EFI_BLOCK_IO_PROTOCOL instance.
279   @param  MediaId                The media id that the write request is for.
280   @param  LBA                    The starting logical block address to read from on the device.
281                                  The caller is responsible for writing to only legitimate locations.
282   @param  BufferSize             The size of the Buffer in bytes. This must be a multiple of the
283                                  intrinsic block size of the device.
284   @param  Buffer                 A pointer to the destination buffer for the data. The caller
285                                  is responsible for either having implicit or explicit ownership
286                                  of the buffer.
287 
288   @retval EFI_SUCCESS                Success
289   @retval EFI_DEVICE_ERROR           Hardware Error
290   @retval EFI_INVALID_PARAMETER      Parameter is error
291   @retval EFI_NO_MEDIA               No media
292   @retval EFI_MEDIA_CHANGED          Media Change
293   @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
294 **/
295 EFI_STATUS
296 EFIAPI
MMCSDBlockWriteBlocks(IN EFI_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA LBA,IN UINTN BufferSize,IN VOID * Buffer)297 MMCSDBlockWriteBlocks (
298   IN  EFI_BLOCK_IO_PROTOCOL   *This,
299   IN  UINT32                  MediaId,
300   IN  EFI_LBA                 LBA,
301   IN  UINTN                   BufferSize,
302   IN  VOID                    *Buffer
303   )
304 {
305   EFI_STATUS                  Status;
306   UINT32                      Address;
307   CARD_DATA                   *CardData;
308   EFI_SD_HOST_IO_PROTOCOL     *SDHostIo;
309   UINT32                      RemainingLength;
310   UINT32                      TransferLength;
311   UINT8                       *BufferPointer;
312   BOOLEAN                     SectorAddressing;
313 
314   DEBUG((EFI_D_INFO, "Write(LBA=%08lx, Buffer=%08x, Size=%08x)\n", LBA, Buffer, BufferSize));
315   Status   = EFI_SUCCESS;
316   CardData  = CARD_DATA_FROM_THIS(This);
317   SDHostIo = CardData->SDHostIo;
318   if ((CardData->CardType == SDMemoryCard2High) || (CardData->CardType == MMCCardHighCap)) {
319     SectorAddressing = TRUE;
320   } else {
321     SectorAddressing = FALSE;
322   }
323   if (SectorAddressing) {
324     //
325     //Block Address
326     //
327     Address = (UINT32)DivU64x32 (MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize), 512);
328   } else {
329     //
330     //Byte Address
331     //
332     Address = (UINT32)MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize);
333   }
334 
335   if (!Buffer) {
336     Status = EFI_INVALID_PARAMETER;
337     DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Invalid parameter \r\n"));
338     goto Done;
339   }
340 
341   if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
342     Status = EFI_BAD_BUFFER_SIZE;
343     DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Bad buffer size \r\n"));
344     goto Done;
345   }
346 
347   if (BufferSize == 0) {
348     Status = EFI_SUCCESS;
349     goto Done;
350   }
351 
352   if (This->Media->ReadOnly == TRUE) {
353     Status = EFI_WRITE_PROTECTED;
354     DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Write protected \r\n"));
355     goto Done;
356   }
357 
358 
359 
360     BufferPointer   = Buffer;
361     RemainingLength = (UINT32)BufferSize;
362 
363     while (RemainingLength > 0) {
364     if ((BufferSize > CardData->BlockIoMedia.BlockSize) ) {
365       if (RemainingLength > SDHostIo->HostCapability.BoundarySize) {
366         TransferLength = SDHostIo->HostCapability.BoundarySize;
367       } else {
368         TransferLength = RemainingLength;
369       }
370 
371       if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {
372 
373         if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3)))  {
374             Status = SendCommand (
375                        CardData,
376                        SET_BLOCKLEN,
377                        CardData->BlockIoMedia.BlockSize,
378                        NoData,
379                        NULL,
380                        0,
381                        ResponseR1,
382                        TIMEOUT_COMMAND,
383                        (UINT32*)&(CardData->CardStatus)
384                        );
385             if (EFI_ERROR (Status)) {
386               break;
387             }
388         }
389         Status = SendCommand (
390                       CardData,
391                    SET_BLOCK_COUNT,
392                    TransferLength / CardData->BlockIoMedia.BlockSize,
393                       NoData,
394                       NULL,
395                       0,
396                       ResponseR1,
397                       TIMEOUT_COMMAND,
398                       (UINT32*)&(CardData->CardStatus)
399                       );
400         if (EFI_ERROR (Status)) {
401           break;
402         }
403       }
404 
405       CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength);
406 
407       Status = SendCommand (
408                  CardData,
409                  WRITE_MULTIPLE_BLOCK,
410                  Address,
411                  OutData,
412                  CardData->AlignedBuffer,
413                  (UINT32)TransferLength,
414                  ResponseR1,
415                  TIMEOUT_DATA,
416                  (UINT32*)&(CardData->CardStatus)
417                  );
418       if (EFI_ERROR (Status)) {
419         DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: WRITE_MULTIPLE_BLOCK -> Fail\n"));
420         break;
421       }
422     } else {
423       if (RemainingLength > CardData->BlockIoMedia.BlockSize) {
424         TransferLength = CardData->BlockIoMedia.BlockSize;
425       } else {
426         TransferLength = RemainingLength;
427       }
428 
429       CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength);
430 
431       Status = SendCommand (
432                  CardData,
433                  WRITE_BLOCK,
434                  Address,
435                  OutData,
436                  CardData->AlignedBuffer,
437                  (UINT32)TransferLength,
438                  ResponseR1,
439                  TIMEOUT_DATA,
440                  (UINT32*)&(CardData->CardStatus)
441                  );
442     }
443     if (SectorAddressing) {
444         //
445         //Block Address
446         //
447         Address += TransferLength / 512;
448       } else {
449         //
450         //Byte Address
451         //
452         Address += TransferLength;
453       }
454       BufferPointer   += TransferLength;
455       RemainingLength -= TransferLength;
456 
457   }
458 
459   if (EFI_ERROR (Status)) {
460     SendCommand (
461       CardData,
462       STOP_TRANSMISSION,
463       0,
464       NoData,
465       NULL,
466       0,
467       ResponseR1b,
468       TIMEOUT_COMMAND,
469       (UINT32*)&(CardData->CardStatus)
470       );
471 
472   }
473 
474 
475 Done:
476   return EFI_SUCCESS;
477 }
478 
479 /**
480   Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function.
481     (In this driver, this function just returns EFI_SUCCESS.)
482 
483   @param  This                   The EFI_BLOCK_IO_PROTOCOL instance.
484 
485   @retval EFI_SUCCESS
486   @retval Others
487 **/
488 EFI_STATUS
489 EFIAPI
MMCSDBlockFlushBlocks(IN EFI_BLOCK_IO_PROTOCOL * This)490 MMCSDBlockFlushBlocks (
491   IN  EFI_BLOCK_IO_PROTOCOL   *This
492   )
493 {
494   return EFI_SUCCESS;
495 }
496 
497 
498 /**
499   MMC/SD card BlockIo init function.
500 
501   @param  CardData               Pointer to CARD_DATA.
502 
503   @retval EFI_SUCCESS
504   @retval Others
505 **/
506 EFI_STATUS
MMCSDBlockIoInit(IN CARD_DATA * CardData)507 MMCSDBlockIoInit (
508   IN  CARD_DATA    *CardData
509   )
510 {
511   //
512   //BlockIO protocol
513   //
514   CardData->BlockIo.Revision    = EFI_BLOCK_IO_PROTOCOL_REVISION;
515   CardData->BlockIo.Media       = &(CardData->BlockIoMedia);
516   CardData->BlockIo.Reset       = MMCSDBlockReset;
517   CardData->BlockIo.ReadBlocks  = MMCSDBlockReadBlocks ;
518   CardData->BlockIo.WriteBlocks = MMCSDBlockWriteBlocks;
519   CardData->BlockIo.FlushBlocks = MMCSDBlockFlushBlocks;
520 
521   CardData->BlockIoMedia.MediaId          = 0;
522   CardData->BlockIoMedia.RemovableMedia   = FALSE;
523   CardData->BlockIoMedia.MediaPresent     = TRUE;
524   CardData->BlockIoMedia.LogicalPartition = FALSE;
525 
526   if (CardData->CSDRegister.PERM_WRITE_PROTECT || CardData->CSDRegister.TMP_WRITE_PROTECT) {
527     CardData->BlockIoMedia.ReadOnly         = TRUE;
528   } else {
529     CardData->BlockIoMedia.ReadOnly         = FALSE;
530   }
531 
532 
533   CardData->BlockIoMedia.WriteCaching     = FALSE;
534   CardData->BlockIoMedia.BlockSize        = CardData->BlockLen;
535   CardData->BlockIoMedia.IoAlign          = 1;
536   CardData->BlockIoMedia.LastBlock        = (EFI_LBA)(CardData->BlockNumber - 1);
537 
538 
539   return EFI_SUCCESS;
540 
541 }
542 
543 
544 
545