sdcard.c
511 lines
| 16.3 KiB
| text/x-c
|
CLexer
r71 | /*------------------------------------------------------------------------------ | |||
-- 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; | ||||
} | ||||