|
|
/*------------------------------------------------------------------------------
|
|
|
-- This file is a part of the libuc, microcontroler library
|
|
|
-- Copyright (C) 2012, Alexis Jeandet
|
|
|
--
|
|
|
-- This program is free software; you can redistribute it and/or modify
|
|
|
-- it under the terms of the GNU General Public License as published by
|
|
|
-- the Free Software Foundation; either version 3 of the License, or
|
|
|
-- (at your option) any later version.
|
|
|
--
|
|
|
-- This program is distributed in the hope that it will be useful,
|
|
|
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
-- GNU General Public License for more details.
|
|
|
--
|
|
|
-- You should have received a copy of the GNU General Public License
|
|
|
-- along with this program; if not, write to the Free Software
|
|
|
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
-------------------------------------------------------------------------------
|
|
|
-- Author : Alexis Jeandet
|
|
|
-- Mail : alexis.jeandet@member.fsf.org
|
|
|
-------------------------------------------------------------------------------*/
|
|
|
#include <sdcard.h>
|
|
|
#include <sdcard-spi.h>
|
|
|
#include <stdio.h>
|
|
|
#include <core.h>
|
|
|
|
|
|
int sdcardselect (blkdeviceptr _this);
|
|
|
void sdcarddeselect (blkdeviceptr _this);
|
|
|
int sdcardwait_ready (sdcardDev* sdcard);
|
|
|
int sdcardxmit_datablock (sdcardDev* sdcard,const char *buff,char token);
|
|
|
int sdcardrcvr_datablock (sdcardDev* sdcard,char *buff,uint32_t btr);
|
|
|
char sdcardsend_cmd (blkdeviceptr _this,char cmd,uint32_t arg);
|
|
|
|
|
|
DSTATUS sdcarddisk_status (blkdeviceptr _this);
|
|
|
DSTATUS sdcarddisk_initialize (blkdeviceptr _this);
|
|
|
DRESULT sdcarddisk_read (blkdeviceptr _this,char *buff,uint32_t sector,char count);
|
|
|
DRESULT sdcarddisk_write (blkdeviceptr _this,const char *buff,uint32_t sector,char count);
|
|
|
DRESULT sdcarddisk_ioctl (blkdeviceptr _this,char ctrl,void *buff);
|
|
|
|
|
|
static volatile
|
|
|
unsigned int Timer1, Timer2; /* 1kHz decrement timer stopped at zero (disk_timerproc()) */
|
|
|
|
|
|
void sdcarddeselect (blkdeviceptr _this)
|
|
|
{
|
|
|
char d;
|
|
|
_this->select(0);
|
|
|
((sdcardDev*)_this->phy)->rcvr_mmc(((sdcardDev*)_this->phy)->phy,&d, 1); /* Dummy clock (force DO hi-z for multiple slave SPI) */
|
|
|
}
|
|
|
|
|
|
int sdcardselect (blkdeviceptr _this) /* 1:OK, 0:Timeout */
|
|
|
{
|
|
|
char d;
|
|
|
_this->select(1);
|
|
|
((sdcardDev*)_this->phy)->rcvr_mmc(((sdcardDev*)_this->phy)->phy,&d, 1); /* Dummy clock (force DO enabled) */
|
|
|
|
|
|
if (sdcardwait_ready(((sdcardDev*)_this->phy))) return 1; /* OK */
|
|
|
_this->select(0);
|
|
|
return 0; /* Timeout */
|
|
|
}
|
|
|
|
|
|
int sdcardwait_ready (sdcardDev* sdcard) /* 1:OK, 0:Timeout */
|
|
|
{
|
|
|
char d=0;
|
|
|
unsigned int tmr;
|
|
|
volatile unsigned int i=0;
|
|
|
|
|
|
for (tmr = 500; tmr>0; tmr--) { /* Wait for ready in timeout of 500ms */
|
|
|
sdcard->rcvr_mmc(sdcard->phy,&d, 1);
|
|
|
if (d == 0xFF) break;
|
|
|
delay_100us(10);
|
|
|
}
|
|
|
|
|
|
return tmr != 0;
|
|
|
}
|
|
|
|
|
|
int sdcardrcvr_datablock (sdcardDev* sdcard,char *buff,uint32_t btr)
|
|
|
{
|
|
|
char d[2];
|
|
|
unsigned int tmr;
|
|
|
volatile unsigned int i=0;
|
|
|
for (tmr = 100; tmr; tmr--) { /* Wait for data packet in timeout of 100ms */
|
|
|
sdcard->rcvr_mmc(sdcard->phy,d, 1);
|
|
|
if (d[0] != 0xFF) break;
|
|
|
delay_100us(10);
|
|
|
}
|
|
|
if (d[0] != 0xFE) return 0; /* If not valid data token, return with error */
|
|
|
|
|
|
sdcard->rcvr_mmc(sdcard->phy,buff, btr); /* Receive the data block into buffer */
|
|
|
sdcard->rcvr_mmc(sdcard->phy,d, 2); /* Discard CRC */
|
|
|
|
|
|
return 1; /* Return with success */
|
|
|
}
|
|
|
|
|
|
|
|
|
int sdcardxmit_datablock (sdcardDev* sdcard,const char *buff,char token)
|
|
|
{
|
|
|
char d[2];
|
|
|
|
|
|
|
|
|
if (!sdcardwait_ready(sdcard)) return 0;
|
|
|
|
|
|
d[0] = token;
|
|
|
sdcard->xmit_mmc(sdcard->phy,d, 1); /* Xmit a token */
|
|
|
if (token != 0xFD) { /* Is it data token? */
|
|
|
sdcard->xmit_mmc(sdcard->phy,buff, 512); /* Xmit the 512 byte data block to MMC */
|
|
|
sdcard->rcvr_mmc(sdcard->phy,d, 2); /* Xmit dummy CRC (0xFF,0xFF) */
|
|
|
sdcard->rcvr_mmc(sdcard->phy,d, 1); /* Receive data response */
|
|
|
if ((d[0] & 0x1F) != 0x05) /* If not accepted, return with error */
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
|
|
|
char sdcardsend_cmd (blkdeviceptr _this,char cmd,uint32_t arg)
|
|
|
{
|
|
|
char n, d, buf[6];
|
|
|
|
|
|
|
|
|
if (cmd & 0x80) { /* ACMD<n> is the command sequense of CMD55-CMD<n> */
|
|
|
cmd &= 0x7F;
|
|
|
n = sdcardsend_cmd(_this,CMD55, 0);
|
|
|
if (n > 1) return n;
|
|
|
}
|
|
|
/* Select the card and wait for ready */
|
|
|
sdcarddeselect(_this);
|
|
|
if (!sdcardselect(_this)) {printf("Can't select SDCARD\n");return 0xFF;}
|
|
|
/* Send a command packet */
|
|
|
buf[0] = 0x40 | cmd; /* Start + Command index */
|
|
|
buf[1] = (char)(arg >> 24); /* Argument[31..24] */
|
|
|
buf[2] = (char)(arg >> 16); /* Argument[23..16] */
|
|
|
buf[3] = (char)(arg >> 8); /* Argument[15..8] */
|
|
|
buf[4] = (char)arg; /* Argument[7..0] */
|
|
|
n = 0x01; /* Dummy CRC + Stop */
|
|
|
if (cmd == CMD0) n = 0x95; /* (valid CRC for CMD0(0)) */
|
|
|
if (cmd == CMD8) n = 0x87; /* (valid CRC for CMD8(0x1AA)) */
|
|
|
if (cmd == CMD55) n = 0x63;
|
|
|
buf[5] = n;
|
|
|
((sdcardDev*)_this->phy)->xmit_mmc(((sdcardDev*)_this->phy)->phy,buf, 6);
|
|
|
/* Receive command response */
|
|
|
if (cmd == CMD12)
|
|
|
{
|
|
|
((sdcardDev*)_this->phy)->rcvr_mmc(((sdcardDev*)_this->phy)->phy,&d, 1);
|
|
|
} /* Skip a stuff byte when stop reading */
|
|
|
n = 100; /* Wait for a valid response in timeout of 100 attempts */
|
|
|
do
|
|
|
{
|
|
|
((sdcardDev*)_this->phy)->rcvr_mmc(((sdcardDev*)_this->phy)->phy,&d, 1);
|
|
|
delay_100us(10);
|
|
|
//libucprintf("resp=%d\n\r",d);
|
|
|
}while ((d & 0x80) && --n);
|
|
|
|
|
|
return d; /* Return with the response value */
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DSTATUS sdcarddisk_status (blkdeviceptr _this)
|
|
|
{
|
|
|
DSTATUS s = ((sdcardDev*)_this->phy)->Stat;
|
|
|
char ocr[4];
|
|
|
|
|
|
|
|
|
if ((_this==0) || !_this->detect()) {
|
|
|
s = STA_NODISK | STA_NOINIT;
|
|
|
} else {
|
|
|
s &= ~STA_NODISK;
|
|
|
if (_this->writeprotected()) /* Check card write protection */
|
|
|
s |= STA_PROTECT;
|
|
|
else
|
|
|
s &= ~STA_PROTECT;
|
|
|
if (!(s & STA_NOINIT)) {
|
|
|
if (sdcardsend_cmd(_this,CMD58, 0)) /* Check if the card is kept initialized */
|
|
|
s |= STA_NOINIT;
|
|
|
((sdcardDev*)_this->phy)->rcvr_mmc(((sdcardDev*)_this->phy)->phy,ocr, 4);
|
|
|
_this->select(0);
|
|
|
}
|
|
|
}
|
|
|
((sdcardDev*)_this->phy)->Stat = s;
|
|
|
|
|
|
return s;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DSTATUS sdcarddisk_initialize (blkdeviceptr _this)
|
|
|
{
|
|
|
char cmd, ty, ocr[4],ocr2[4];
|
|
|
int n;
|
|
|
const char dummy=0xff;
|
|
|
uint32_t speed = 1000000;
|
|
|
|
|
|
((sdcardDev*)_this->phy)->setspeed(((sdcardDev*)_this->phy)->phy,350000);
|
|
|
if (_this==0) return STA_NOINIT; /* Supports only drive 0 */
|
|
|
/* Is card existing in the soket? */
|
|
|
if (((sdcardDev*)_this->phy)->Stat & STA_NODISK)
|
|
|
{
|
|
|
printf("No SDCARD\n");
|
|
|
return ((sdcardDev*)_this->phy)->Stat;
|
|
|
}
|
|
|
printf("SDCARD Detected\n");
|
|
|
for (n = 100; n; n--) ((sdcardDev*)_this->phy)->xmit_mmc(((sdcardDev*)_this->phy)->phy,&dummy, 1); /* Send 80 dummy clocks */
|
|
|
|
|
|
ty = 0;
|
|
|
if (sdcardsend_cmd(_this,CMD0, 0) == 1) { /* Put the card SPI/Idle state */
|
|
|
printf("SDCARD in Idle mode\n");
|
|
|
Timer1 = 1000; /* Initialization timeout = 1 sec */
|
|
|
if (sdcardsend_cmd(_this,CMD8, 0x1AA) == 1) { /* SDv2? */
|
|
|
printf("SDCARD V2\n");
|
|
|
((sdcardDev*)_this->phy)->rcvr_mmc(((sdcardDev*)_this->phy)->phy,ocr, 4);
|
|
|
//for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF); /* Get 32 bit return value of R7 resp */
|
|
|
if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* Is the card supports vcc of 2.7-3.6V? */
|
|
|
printf("The card supports vcc of 2.7-3.6V\n");
|
|
|
while (Timer1 && sdcardsend_cmd(_this,ACMD41, 1UL << 30)) ; /* Wait for end of initialization with ACMD41(HCS) */
|
|
|
if (Timer1 && sdcardsend_cmd(_this,CMD58, 0) == 0) { /* Check CCS bit in the OCR */
|
|
|
//for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF);
|
|
|
printf("Check CCS bit in the OCR:\n");
|
|
|
((sdcardDev*)_this->phy)->rcvr_mmc(((sdcardDev*)_this->phy)->phy,ocr, 4);
|
|
|
printf("OCR[0]=0x%X\n",ocr[0]);
|
|
|
ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* Card id SDv2 */
|
|
|
}
|
|
|
}
|
|
|
} else { /* Not SDv2 card */
|
|
|
if (sdcardsend_cmd(_this,ACMD41, 0) <= 1) { /* SDv1 or MMC? */
|
|
|
ty = CT_SD1; cmd = ACMD41; /* SDv1 (ACMD41(0)) */
|
|
|
} else {
|
|
|
ty = CT_MMC; cmd = CMD1; /* MMCv3 (CMD1(0)) */
|
|
|
}
|
|
|
while (Timer1 && sdcardsend_cmd(_this,cmd, 0)) ; /* Wait for end of initialization */
|
|
|
if (!Timer1 || sdcardsend_cmd(_this,CMD16, 512) != 0) /* Set block length: 512 */
|
|
|
ty = 0;
|
|
|
}
|
|
|
}
|
|
|
((sdcardDev*)_this->phy)->CardType = ty; /* Card type */
|
|
|
printf("CardType=0x%X\n",ty);
|
|
|
|
|
|
if (ty) { /* OK */
|
|
|
((sdcardDev*)_this->phy)->Stat &= ~STA_NOINIT; /* Clear STA_NOINIT flag */
|
|
|
sdcardsend_cmd(_this,CMD58, 0);
|
|
|
((sdcardDev*)_this->phy)->rcvr_mmc(((sdcardDev*)_this->phy)->phy,ocr, 4);
|
|
|
do
|
|
|
{
|
|
|
speed+=1000000;
|
|
|
((sdcardDev*)_this->phy)->setspeed(((sdcardDev*)_this->phy)->phy,speed);
|
|
|
sdcardsend_cmd(_this,CMD58, 0);
|
|
|
((sdcardDev*)_this->phy)->rcvr_mmc(((sdcardDev*)_this->phy)->phy,ocr2, 4);
|
|
|
for(n=0;n<4;n++)
|
|
|
{
|
|
|
if(ocr[n]!=ocr2[n])
|
|
|
{
|
|
|
n=0;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
if((speed>(50*1000*1000)) || (speed >= getCpuFreq()))
|
|
|
{
|
|
|
break;
|
|
|
}
|
|
|
}while(n);
|
|
|
if(!n)
|
|
|
{
|
|
|
speed-=1000000;
|
|
|
((sdcardDev*)_this->phy)->setspeed(((sdcardDev*)_this->phy)->phy,speed);
|
|
|
}
|
|
|
printf("SDCARD speed = %dMHz\n",speed/1000000);
|
|
|
|
|
|
} else { /* Failed */
|
|
|
//power_off();
|
|
|
((sdcardDev*)_this->phy)->Stat = STA_NOINIT;
|
|
|
}
|
|
|
sdcarddeselect (_this);
|
|
|
return ((sdcardDev*)_this->phy)->Stat;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DRESULT sdcarddisk_read (blkdeviceptr _this,char *buff,uint32_t sector,char count)
|
|
|
{
|
|
|
DSTATUS s;
|
|
|
|
|
|
|
|
|
s = sdcarddisk_status(_this);
|
|
|
if (s & STA_NOINIT) return RES_NOTRDY;
|
|
|
if (!count) return RES_PARERR;
|
|
|
if (!(((sdcardDev*)_this->phy)->CardType & CT_BLOCK)) sector *= 512; /* Convert LBA to byte address if needed */
|
|
|
|
|
|
if (count == 1) { /* Single block read */
|
|
|
if ((sdcardsend_cmd(_this,CMD17, sector) == 0) && sdcardrcvr_datablock((sdcardDev*)(_this->phy),buff, 512))
|
|
|
count = 0;
|
|
|
}
|
|
|
else { /* Multiple block read */
|
|
|
if (sdcardsend_cmd(_this,CMD18, sector) == 0) { /* READ_MULTIPLE_BLOCK */
|
|
|
do {
|
|
|
if (!sdcardrcvr_datablock (((sdcardDev*)_this->phy),buff, 512)) break;
|
|
|
buff += 512;
|
|
|
} while (--count);
|
|
|
sdcardsend_cmd(_this,CMD12, 0); /* STOP_TRANSMISSION */
|
|
|
}
|
|
|
}
|
|
|
sdcarddeselect (_this);
|
|
|
|
|
|
return count ? RES_ERROR : RES_OK;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DRESULT sdcarddisk_write (blkdeviceptr _this,const char *buff,uint32_t sector,char count)
|
|
|
{
|
|
|
DSTATUS s;
|
|
|
|
|
|
|
|
|
s = sdcarddisk_status(_this);
|
|
|
if (s & STA_NOINIT) return RES_NOTRDY;
|
|
|
if (s & STA_PROTECT) return RES_WRPRT;
|
|
|
if (!count) return RES_PARERR;
|
|
|
if (!(((sdcardDev*)_this->phy)->CardType & CT_BLOCK)) sector *= 512; /* Convert LBA to byte address if needed */
|
|
|
|
|
|
if (count == 1) { /* Single block write */
|
|
|
if ((sdcardsend_cmd(_this,CMD24, sector) == 0) /* WRITE_BLOCK */
|
|
|
&& sdcardxmit_datablock (((sdcardDev*)_this->phy),buff, 0xFE))
|
|
|
count = 0;
|
|
|
}
|
|
|
else { /* Multiple block write */
|
|
|
if (((sdcardDev*)_this->phy)->CardType & CT_SDC) sdcardsend_cmd(_this,ACMD23, count);
|
|
|
if (sdcardsend_cmd(_this,CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */
|
|
|
do {
|
|
|
if (!sdcardxmit_datablock (((sdcardDev*)_this->phy),buff, 0xFC)) break;
|
|
|
buff += 512;
|
|
|
} while (--count);
|
|
|
if (!sdcardxmit_datablock (((sdcardDev*)_this->phy),0, 0xFD)) /* STOP_TRAN token */
|
|
|
count = 1;
|
|
|
}
|
|
|
}
|
|
|
sdcarddeselect (_this);
|
|
|
|
|
|
return count ? RES_ERROR : RES_OK;
|
|
|
}
|
|
|
|
|
|
|
|
|
DRESULT sdcarddisk_ioctl (blkdeviceptr _this,char ctrl,void *buff)
|
|
|
{
|
|
|
DRESULT res;
|
|
|
const char dummy=0xff;
|
|
|
char n, csd[16], *ptr = buff;
|
|
|
uint16_t csize;
|
|
|
uint32_t *dp, st, ed;
|
|
|
|
|
|
|
|
|
if (_this==0) return RES_PARERR; /* Check parameter */
|
|
|
if (((sdcardDev*)_this->phy)->Stat & STA_NOINIT) return RES_NOTRDY; /* Check if drive is ready */
|
|
|
|
|
|
res = RES_ERROR;
|
|
|
|
|
|
switch (ctrl) {
|
|
|
case CTRL_SYNC : /* Wait for end of internal write process of the drive */
|
|
|
if (sdcardselect (_this)) {
|
|
|
sdcarddeselect (_this);
|
|
|
res = RES_OK;
|
|
|
}
|
|
|
break;
|
|
|
|
|
|
case GET_SECTOR_COUNT : /* Get drive capacity in unit of sector (DWORD) */
|
|
|
if ((sdcardsend_cmd(_this,CMD9, 0) == 0) && sdcardrcvr_datablock (((sdcardDev*)_this->phy),csd, 16)) {
|
|
|
if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */
|
|
|
csize = csd[9] + ((uint16_t)csd[8] << 8) + 1;
|
|
|
*(uint32_t*)buff = (uint32_t)csize << 10;
|
|
|
} else { /* SDC ver 1.XX or MMC ver 3 */
|
|
|
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
|
|
|
csize = (csd[8] >> 6) + ((uint16_t)csd[7] << 2) + ((uint16_t)(csd[6] & 3) << 10) + 1;
|
|
|
*(uint32_t*)buff = (uint32_t)csize << (n - 9);
|
|
|
}
|
|
|
res = RES_OK;
|
|
|
}
|
|
|
break;
|
|
|
|
|
|
case GET_SECTOR_SIZE : /* Get sector size in unit of byte (WORD) */
|
|
|
*(uint16_t*)buff = 512;
|
|
|
res = RES_OK;
|
|
|
break;
|
|
|
|
|
|
case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */
|
|
|
if (((sdcardDev*)_this->phy)->CardType & CT_SD2) { /* SDC ver 2.00 */
|
|
|
if (sdcardsend_cmd(_this,ACMD13, 0) == 0) { /* Read SD status */
|
|
|
((sdcardDev*)_this->phy)->xmit_mmc(((sdcardDev*)_this->phy)->phy,&dummy, 1);
|
|
|
if (sdcardrcvr_datablock (((sdcardDev*)_this->phy),csd, 16)) { /* Read partial block */
|
|
|
for (n = 64 - 16; n; n--) ((sdcardDev*)_this->phy)->xmit_mmc(((sdcardDev*)_this->phy)->phy,&dummy, 1); /* Purge trailing data */
|
|
|
*(uint32_t*)buff = 16UL << (csd[10] >> 4);
|
|
|
res = RES_OK;
|
|
|
((sdcardDev*)_this->phy)->xmit_mmc(((sdcardDev*)_this->phy)->phy,&dummy, 1);
|
|
|
}
|
|
|
}
|
|
|
} else { /* SDC ver 1.XX or MMC */
|
|
|
if ((sdcardsend_cmd(_this,CMD9, 0) == 0) && sdcardrcvr_datablock (((sdcardDev*)_this->phy),csd, 16)) { /* Read CSD */
|
|
|
if (((sdcardDev*)_this->phy)->CardType & CT_SD1) { /* SDC ver 1.XX */
|
|
|
*(uint32_t*)buff = (((csd[10] & 63) << 1) + ((uint16_t)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1);
|
|
|
} else { /* MMC */
|
|
|
*(uint32_t*)buff = ((uint16_t)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1);
|
|
|
}
|
|
|
res = RES_OK;
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
|
|
|
|
case CTRL_ERASE_SECTOR : /* Erase a block of sectors (used when _USE_ERASE == 1) */
|
|
|
if (!(((sdcardDev*)_this->phy)->CardType & CT_SDC)) break; /* Check if the card is SDC */
|
|
|
if (sdcarddisk_ioctl(_this, MMC_GET_CSD, csd)) break; /* Get CSD */
|
|
|
if (!(csd[0] >> 6) && !(csd[10] & 0x40)) break; /* Check if sector erase can be applied to the card */
|
|
|
dp = buff; st = dp[0]; ed = dp[1]; /* Load sector block */
|
|
|
if (!(((sdcardDev*)_this->phy)->CardType & CT_BLOCK)) {
|
|
|
st *= 512; ed *= 512;
|
|
|
}
|
|
|
if (sdcardsend_cmd(_this,CMD32, st) == 0 && sdcardsend_cmd(_this,CMD33, ed) == 0 && sdcardsend_cmd(_this,CMD38, 0) == 0 && sdcardwait_ready(((sdcardDev*)_this->phy))) /* Erase sector block */
|
|
|
res = RES_OK; /* FatFs does not check result of this command */
|
|
|
break;
|
|
|
|
|
|
/* Following command are not used by FatFs module */
|
|
|
|
|
|
case MMC_GET_TYPE : /* Get MMC/SDC type (BYTE) */
|
|
|
*ptr = ((sdcardDev*)_this->phy)->CardType;
|
|
|
res = RES_OK;
|
|
|
break;
|
|
|
|
|
|
case MMC_GET_CSD : /* Read CSD (16 bytes) */
|
|
|
if (sdcardsend_cmd(_this,CMD9, 0) == 0 /* READ_CSD */
|
|
|
&& sdcardrcvr_datablock (((sdcardDev*)_this->phy),ptr, 16))
|
|
|
res = RES_OK;
|
|
|
break;
|
|
|
|
|
|
case MMC_GET_CID : /* Read CID (16 bytes) */
|
|
|
if (sdcardsend_cmd(_this,CMD10, 0) == 0 /* READ_CID */
|
|
|
&& sdcardrcvr_datablock (((sdcardDev*)_this->phy),ptr, 16))
|
|
|
res = RES_OK;
|
|
|
break;
|
|
|
|
|
|
case MMC_GET_OCR : /* Read OCR (4 bytes) */
|
|
|
if (sdcardsend_cmd(_this,CMD58, 0) == 0) { /* READ_OCR */
|
|
|
//for (n = 4; n; n--) *ptr++ =
|
|
|
((sdcardDev*)_this->phy)->rcvr_mmc(((sdcardDev*)_this->phy)->phy,ptr, 4);
|
|
|
res = RES_OK;
|
|
|
}
|
|
|
break;
|
|
|
|
|
|
case MMC_GET_SDSTAT : /* Read SD status (64 bytes) */
|
|
|
if (sdcardsend_cmd(_this,ACMD13, 0) == 0) { /* SD_STATUS */
|
|
|
((sdcardDev*)_this->phy)->xmit_mmc(((sdcardDev*)_this->phy)->phy,&dummy, 1);
|
|
|
if (sdcardrcvr_datablock (((sdcardDev*)_this->phy),ptr, 64))
|
|
|
res = RES_OK;
|
|
|
}
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
res = RES_PARERR;
|
|
|
}
|
|
|
|
|
|
sdcarddeselect (_this);
|
|
|
|
|
|
return res;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void sdcardspimake(sdcardDev* sdcard,UHANDLE phy,void (*rcvr_mmc) (UHANDLE,char *,uint32_t),void (*xmit_mmc) (UHANDLE,const char *,uint32_t ),void (*setspeed) (UHANDLE phy,uint32_t speed),uint32_t (*getspeed) (UHANDLE phy))
|
|
|
{
|
|
|
sdcard->phy = phy;
|
|
|
sdcard->rcvr_mmc = rcvr_mmc;
|
|
|
sdcard->xmit_mmc = xmit_mmc;
|
|
|
sdcard->setspeed = setspeed;
|
|
|
sdcard->getspeed = getspeed;
|
|
|
}
|
|
|
|
|
|
void sdcardspimakeblkdev(blkdevice* dev,sdcardDev* sdcard, blkdevselect_t select,blkdevpower_t power,blkdevdetect_t detect,blkdevwriteprotected_t writeprotected)
|
|
|
{
|
|
|
dev->phy=sdcard;
|
|
|
dev->select=select;
|
|
|
dev->power = power;
|
|
|
dev->detect = detect;
|
|
|
dev->writeprotected = writeprotected;
|
|
|
dev->write = sdcarddisk_write;
|
|
|
dev->read = sdcarddisk_read;
|
|
|
dev->ioctl = sdcarddisk_ioctl;
|
|
|
dev->initialize = sdcarddisk_initialize;
|
|
|
dev->status = sdcarddisk_status;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|