sd-card.c revision 225736
1191783Srmacklem/*- 2191783Srmacklem * Copyright (c) 2006 M. Warner Losh. All rights reserved. 3191783Srmacklem * 4191783Srmacklem * Redistribution and use in source and binary forms, with or without 5191783Srmacklem * modification, are permitted provided that the following conditions 6191783Srmacklem * are met: 7191783Srmacklem * 1. Redistributions of source code must retain the above copyright 8191783Srmacklem * notice, this list of conditions and the following disclaimer. 9191783Srmacklem * 2. Redistributions in binary form must reproduce the above copyright 10191783Srmacklem * notice, this list of conditions and the following disclaimer in the 11191783Srmacklem * documentation and/or other materials provided with the distribution. 12191783Srmacklem * 13191783Srmacklem * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14191783Srmacklem * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15191783Srmacklem * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16191783Srmacklem * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17191783Srmacklem * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18191783Srmacklem * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19191783Srmacklem * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20191783Srmacklem * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21191783Srmacklem * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22191783Srmacklem * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23191783Srmacklem * 24191783Srmacklem * This software is derived from software provide by Kwikbyte who specifically 25191783Srmacklem * disclaimed copyright on the code. 26191783Srmacklem * 27191783Srmacklem * $FreeBSD: stable/9/sys/boot/arm/at91/libat91/sd-card.c 168011 2007-03-28 22:31:32Z imp $ 28191783Srmacklem */ 29191783Srmacklem 30191783Srmacklem//*---------------------------------------------------------------------------- 31191783Srmacklem//* ATMEL Microcontroller Software Support - ROUSSET - 32191783Srmacklem//*---------------------------------------------------------------------------- 33191783Srmacklem//* The software is delivered "AS IS" without warranty or condition of any 34191783Srmacklem//* kind, either express, implied or statutory. This includes without 35191783Srmacklem//* limitation any warranty or condition with respect to merchantability or 36191783Srmacklem//* fitness for any particular purpose, or against the infringements of 37191783Srmacklem//* intellectual property rights of others. 38191783Srmacklem//*---------------------------------------------------------------------------- 39191783Srmacklem//* File Name : main.c 40191783Srmacklem//* Object : main application written in C 41191783Srmacklem//* Creation : FB 21/11/2002 42191783Srmacklem//* 43191783Srmacklem//*---------------------------------------------------------------------------- 44191783Srmacklem#include "at91rm9200.h" 45191783Srmacklem#include "lib_AT91RM9200.h" 46191783Srmacklem#include "mci_device.h" 47191783Srmacklem#include "lib.h" 48191783Srmacklem#include "sd-card.h" 49191783Srmacklem 50191783Srmacklem#define AT91C_MCI_TIMEOUT 1000000 /* For AT91F_MCIDeviceWaitReady */ 51191783Srmacklem#define BUFFER_SIZE_MCI_DEVICE 512 52191783Srmacklem#define MASTER_CLOCK 60000000 53191783Srmacklem 54191783Srmacklem//* Global Variables 55191783SrmacklemAT91S_MciDevice MCI_Device; 56191783Srmacklemchar Buffer[BUFFER_SIZE_MCI_DEVICE]; 57191783Srmacklem 58191783Srmacklem/****************************************************************************** 59191783Srmacklem**Error return codes 60191783Srmacklem******************************************************************************/ 61191783Srmacklem#define MCI_UNSUPP_SIZE_ERROR 5 62191783Srmacklem#define MCI_UNSUPP_OFFSET_ERROR 6 63191783Srmacklem 64191783Srmacklem//*---------------------------------------------------------------------------- 65191783Srmacklem//* \fn MCIDeviceWaitReady 66191783Srmacklem//* \brief Wait for MCI Device ready 67191783Srmacklem//*---------------------------------------------------------------------------- 68191783Srmacklemstatic void 69191783SrmacklemMCIDeviceWaitReady(unsigned int timeout) 70191783Srmacklem{ 71191783Srmacklem volatile int status; 72191783Srmacklem 73191783Srmacklem do 74191783Srmacklem { 75191783Srmacklem status = AT91C_BASE_MCI->MCI_SR; 76191783Srmacklem timeout--; 77191783Srmacklem } 78191783Srmacklem while( !(status & AT91C_MCI_NOTBUSY) && (timeout>0) ); 79191783Srmacklem 80191783Srmacklem status = AT91C_BASE_MCI->MCI_SR; 81191783Srmacklem 82191783Srmacklem // If End of Tx Buffer Empty interrupt occurred 83191783Srmacklem if (MCI_Device.state == AT91C_MCI_TX_SINGLE_BLOCK && status & AT91C_MCI_TXBUFE) { 84191783Srmacklem AT91C_BASE_MCI->MCI_IDR = AT91C_MCI_TXBUFE; 85191783Srmacklem AT91C_BASE_PDC_MCI->PDC_PTCR = AT91C_PDC_TXTDIS; 86191783Srmacklem MCI_Device.state = AT91C_MCI_IDLE; 87191783Srmacklem } // End of if AT91C_MCI_TXBUFF 88191783Srmacklem 89191783Srmacklem // If End of Rx Buffer Full interrupt occurred 90191783Srmacklem if (MCI_Device.state == AT91C_MCI_RX_SINGLE_BLOCK && status & AT91C_MCI_RXBUFF) { 91191783Srmacklem AT91C_BASE_MCI->MCI_IDR = AT91C_MCI_RXBUFF; 92191783Srmacklem AT91C_BASE_PDC_MCI->PDC_PTCR = AT91C_PDC_RXTDIS; 93191783Srmacklem MCI_Device.state = AT91C_MCI_IDLE; 94191783Srmacklem } // End of if AT91C_MCI_RXBUFF 95191783Srmacklem} 96191783Srmacklem 97191783Srmackleminline static unsigned int 98191783Srmacklemswap(unsigned int a) 99191783Srmacklem{ 100191783Srmacklem return (((a & 0xff) << 24) | ((a & 0xff00) << 8) | ((a & 0xff0000) >> 8) 101191783Srmacklem | ((a & 0xff000000) >> 24)); 102191783Srmacklem} 103191783Srmacklem 104191783Srmackleminline static void 105191783Srmacklemwait_ready() 106191783Srmacklem{ 107191783Srmacklem int status; 108191783Srmacklem 109191783Srmacklem // wait for CMDRDY Status flag to read the response 110191783Srmacklem do 111191783Srmacklem { 112191783Srmacklem status = AT91C_BASE_MCI->MCI_SR; 113191783Srmacklem } while( !(status & AT91C_MCI_CMDRDY) ); 114191783Srmacklem} 115191783Srmacklem 116191783Srmacklem//*---------------------------------------------------------------------------- 117191783Srmacklem//* \fn MCI_SendCommand 118191783Srmacklem//* \brief Generic function to send a command to the MMC or SDCard 119191783Srmacklem//*---------------------------------------------------------------------------- 120191783Srmacklemstatic int 121191783SrmacklemMCI_SendCommand( 122191783Srmacklem unsigned int Cmd, 123191783Srmacklem unsigned int Arg) 124191783Srmacklem{ 125191783Srmacklem unsigned int error; 126191783Srmacklem 127191783Srmacklem AT91C_BASE_MCI->MCI_ARGR = Arg; 128191783Srmacklem AT91C_BASE_MCI->MCI_CMDR = Cmd; 129191783Srmacklem 130191783Srmacklem// printf("CMDR %x ARG %x\n", Cmd, Arg); 131191783Srmacklem wait_ready(); 132191783Srmacklem // Test error ==> if crc error and response R3 ==> don't check error 133191783Srmacklem error = (AT91C_BASE_MCI->MCI_SR) & AT91C_MCI_SR_ERROR; 134191783Srmacklem if (error != 0) { 135191783Srmacklem if (error != AT91C_MCI_RCRCE) 136191783Srmacklem return (1); 137191783Srmacklem } 138191783Srmacklem return 0; 139191783Srmacklem} 140191783Srmacklem 141191783Srmacklem//*---------------------------------------------------------------------------- 142191783Srmacklem//* \fn MCI_GetStatus 143191783Srmacklem//* \brief Addressed card sends its status register 144191783Srmacklem//*---------------------------------------------------------------------------- 145191783Srmacklemstatic unsigned int 146191783SrmacklemMCI_GetStatus() 147191783Srmacklem{ 148191783Srmacklem if (MCI_SendCommand(SEND_STATUS_CMD, MCI_Device.RCA << 16)) 149191783Srmacklem return AT91C_CMD_SEND_ERROR; 150191783Srmacklem return (AT91C_BASE_MCI->MCI_RSPR[0]); 151191783Srmacklem} 152191783Srmacklem 153191783Srmacklem//*---------------------------------------------------------------------------- 154191783Srmacklem//* \fn MCI_ReadBlock 155191783Srmacklem//* \brief Read an ENTIRE block or PARTIAL block 156191783Srmacklem//*---------------------------------------------------------------------------- 157191783Srmacklemstatic int 158191783SrmacklemMCI_ReadBlock(int src, unsigned int *dataBuffer, int sizeToRead) 159191783Srmacklem{ 160191783Srmacklem// unsigned log2sl = MCI_Device.READ_BL_LEN; 161191783Srmacklem// unsigned sectorLength = 1 << log2sl; 162191783Srmacklem unsigned sectorLength = 512; 163191783Srmacklem 164191783Srmacklem /////////////////////////////////////////////////////////////////////// 165191783Srmacklem if (MCI_Device.state != AT91C_MCI_IDLE) 166191783Srmacklem return 1; 167191783Srmacklem 168191783Srmacklem if ((MCI_GetStatus() & AT91C_SR_READY_FOR_DATA) == 0) 169191783Srmacklem return 1; 170191783Srmacklem 171191783Srmacklem /////////////////////////////////////////////////////////////////////// 172191783Srmacklem 173191783Srmacklem // Init Mode Register 174191783Srmacklem AT91C_BASE_MCI->MCI_MR |= ((sectorLength << 16) | AT91C_MCI_PDCMODE); 175191783Srmacklem 176191783Srmacklem sizeToRead = sizeToRead / 4; 177191783Srmacklem 178191783Srmacklem AT91C_BASE_PDC_MCI->PDC_PTCR = (AT91C_PDC_TXTDIS | AT91C_PDC_RXTDIS); 179191783Srmacklem AT91C_BASE_PDC_MCI->PDC_RPR = (unsigned int)dataBuffer; 180191783Srmacklem AT91C_BASE_PDC_MCI->PDC_RCR = sizeToRead; 181191783Srmacklem 182191783Srmacklem // Send the Read single block command 183191783Srmacklem if (MCI_SendCommand(READ_SINGLE_BLOCK_CMD, src)) 184191783Srmacklem return AT91C_READ_ERROR; 185191783Srmacklem MCI_Device.state = AT91C_MCI_RX_SINGLE_BLOCK; 186191783Srmacklem 187191783Srmacklem // Enable AT91C_MCI_RXBUFF Interrupt 188191783Srmacklem AT91C_BASE_MCI->MCI_IER = AT91C_MCI_RXBUFF; 189191783Srmacklem 190191783Srmacklem // (PDC) Receiver Transfer Enable 191191783Srmacklem AT91C_BASE_PDC_MCI->PDC_PTCR = AT91C_PDC_RXTEN; 192191783Srmacklem 193191783Srmacklem return 0; 194191783Srmacklem} 195191783Srmacklem 196191783Srmacklemint 197191783SrmacklemMCI_read(char* dest, unsigned source, unsigned length) 198191783Srmacklem{ 199191783Srmacklem// unsigned log2sl = MCI_Device.READ_BL_LEN; 200191783Srmacklem// unsigned sectorLength = 1 << log2sl; 201191783Srmacklem unsigned sectorLength = 512; 202191783Srmacklem int sizeToRead; 203191783Srmacklem unsigned int *walker; 204191783Srmacklem 205191783Srmacklem //As long as there is data to read 206191783Srmacklem while (length) 207191783Srmacklem { 208191783Srmacklem if (length > sectorLength) 209191783Srmacklem sizeToRead = sectorLength; 210191783Srmacklem else 211191783Srmacklem sizeToRead = length; 212191783Srmacklem 213191783Srmacklem MCIDeviceWaitReady(AT91C_MCI_TIMEOUT); 214191783Srmacklem //Do the reading 215191783Srmacklem if (MCI_ReadBlock(source, 216191783Srmacklem (unsigned int*)dest, sizeToRead)) 217191783Srmacklem return -1; 218191783Srmacklem 219191783Srmacklem //* Wait MCI Device Ready 220191783Srmacklem MCIDeviceWaitReady(AT91C_MCI_TIMEOUT); 221191783Srmacklem 222191783Srmacklem // Fix erratum in MCI part 223191783Srmacklem for (walker = (unsigned int *)dest; 224191783Srmacklem walker < (unsigned int *)(dest + sizeToRead); walker++) 225191783Srmacklem *walker = swap(*walker); 226191783Srmacklem 227191783Srmacklem //Update counters & pointers 228191783Srmacklem length -= sizeToRead; 229191783Srmacklem dest += sizeToRead; 230191783Srmacklem source += sizeToRead; 231191783Srmacklem } 232191783Srmacklem 233191783Srmacklem return 0; 234191783Srmacklem} 235191783Srmacklem 236191783Srmacklem//*---------------------------------------------------------------------------- 237191783Srmacklem//* \fn MCI_SDCard_SendAppCommand 238191783Srmacklem//* \brief Specific function to send a specific command to the SDCard 239191783Srmacklem//*---------------------------------------------------------------------------- 240191783Srmacklemstatic int 241191783SrmacklemMCI_SDCard_SendAppCommand( 242191783Srmacklem unsigned int Cmd_App, 243191783Srmacklem unsigned int Arg) 244191783Srmacklem{ 245191783Srmacklem // Send the CMD55 for application specific command 246191783Srmacklem AT91C_BASE_MCI->MCI_ARGR = (MCI_Device.RCA << 16 ); 247191783Srmacklem AT91C_BASE_MCI->MCI_CMDR = APP_CMD; 248191783Srmacklem 249191783Srmacklem wait_ready(); 250191783Srmacklem // if an error occurs 251191783Srmacklem if (AT91C_BASE_MCI->MCI_SR & AT91C_MCI_SR_ERROR) 252191783Srmacklem return (1); 253191783Srmacklem return (MCI_SendCommand(Cmd_App,Arg)); 254191783Srmacklem} 255191783Srmacklem 256191783Srmacklem//*---------------------------------------------------------------------------- 257191783Srmacklem//* \fn MCI_GetCSD 258191783Srmacklem//* \brief Asks to the specified card to send its CSD 259191783Srmacklem//*---------------------------------------------------------------------------- 260191783Srmacklemstatic int 261191783SrmacklemMCI_GetCSD(unsigned int rca, unsigned int *response) 262191783Srmacklem{ 263191783Srmacklem 264191783Srmacklem if (MCI_SendCommand(SEND_CSD_CMD, (rca << 16))) 265191783Srmacklem return 1; 266191783Srmacklem 267191783Srmacklem response[0] = AT91C_BASE_MCI->MCI_RSPR[0]; 268191783Srmacklem response[1] = AT91C_BASE_MCI->MCI_RSPR[1]; 269191783Srmacklem response[2] = AT91C_BASE_MCI->MCI_RSPR[2]; 270191783Srmacklem response[3] = AT91C_BASE_MCI->MCI_RSPR[3]; 271191783Srmacklem 272191783Srmacklem return 0; 273191783Srmacklem} 274191783Srmacklem 275191783Srmacklem//*---------------------------------------------------------------------------- 276191783Srmacklem//* \fn MCI_SDCard_GetOCR 277191783Srmacklem//* \brief Asks to all cards to send their operations conditions 278191783Srmacklem//*---------------------------------------------------------------------------- 279191783Srmacklemstatic int 280191783SrmacklemMCI_SDCard_GetOCR() 281191783Srmacklem{ 282191783Srmacklem unsigned int response=0x0; 283191783Srmacklem 284191783Srmacklem // The RCA to be used for CMD55 in Idle state shall be the card's default RCA=0x0000. 285191783Srmacklem MCI_Device.RCA = 0x0; 286191783Srmacklem 287191783Srmacklem while( (response & AT91C_CARD_POWER_UP_BUSY) != AT91C_CARD_POWER_UP_BUSY ) { 288191783Srmacklem if (MCI_SDCard_SendAppCommand(SDCARD_APP_OP_COND_CMD, 289191783Srmacklem AT91C_MMC_HOST_VOLTAGE_RANGE)) 290191783Srmacklem return 1; 291191783Srmacklem response = AT91C_BASE_MCI->MCI_RSPR[0]; 292191783Srmacklem } 293191783Srmacklem return (0); 294191783Srmacklem} 295191783Srmacklem 296191783Srmacklem//*---------------------------------------------------------------------------- 297191783Srmacklem//* \fn MCI_SDCard_GetCID 298191783Srmacklem//* \brief Asks to the SDCard on the chosen slot to send its CID 299191783Srmacklem//*---------------------------------------------------------------------------- 300191783Srmacklemstatic int 301191783SrmacklemMCI_SDCard_GetCID(unsigned int *response) 302191783Srmacklem{ 303191783Srmacklem if (MCI_SendCommand(ALL_SEND_CID_CMD, AT91C_NO_ARGUMENT)) 304191783Srmacklem return 1; 305191783Srmacklem 306191783Srmacklem response[0] = AT91C_BASE_MCI->MCI_RSPR[0]; 307191783Srmacklem response[1] = AT91C_BASE_MCI->MCI_RSPR[1]; 308191783Srmacklem response[2] = AT91C_BASE_MCI->MCI_RSPR[2]; 309191783Srmacklem response[3] = AT91C_BASE_MCI->MCI_RSPR[3]; 310191783Srmacklem 311191783Srmacklem return 0; 312191783Srmacklem} 313191783Srmacklem 314191783Srmacklem//*---------------------------------------------------------------------------- 315191783Srmacklem//* \fn MCI_SDCard_SetBusWidth 316191783Srmacklem//* \brief Set bus width for SDCard 317191783Srmacklem//*---------------------------------------------------------------------------- 318191783Srmacklemstatic int 319191783SrmacklemMCI_SDCard_SetBusWidth() 320191783Srmacklem{ 321191783Srmacklem volatile int ret_value; 322191783Srmacklem char bus_width; 323191783Srmacklem 324191783Srmacklem do { 325191783Srmacklem ret_value=MCI_GetStatus(); 326191783Srmacklem } 327191783Srmacklem while((ret_value > 0) && ((ret_value & AT91C_SR_READY_FOR_DATA) == 0)); 328191783Srmacklem 329191783Srmacklem // Select Card 330191783Srmacklem MCI_SendCommand(SEL_DESEL_CARD_CMD, (MCI_Device.RCA)<<16); 331191783Srmacklem 332191783Srmacklem // Set bus width for Sdcard 333191783Srmacklem if (MCI_Device.SDCard_bus_width == AT91C_MCI_SCDBUS) 334191783Srmacklem bus_width = AT91C_BUS_WIDTH_4BITS; 335191783Srmacklem else 336191783Srmacklem bus_width = AT91C_BUS_WIDTH_1BIT; 337191783Srmacklem 338191783Srmacklem if (MCI_SDCard_SendAppCommand( 339191783Srmacklem SDCARD_SET_BUS_WIDTH_CMD,bus_width) != AT91C_CMD_SEND_OK) 340191783Srmacklem return 1; 341191783Srmacklem 342191783Srmacklem return 0; 343191783Srmacklem} 344191783Srmacklem 345191783Srmacklem//*---------------------------------------------------------------------------- 346191783Srmacklem//* \fn main 347191783Srmacklem//* \brief main function 348191783Srmacklem//*---------------------------------------------------------------------------- 349191783Srmacklemint 350191783Srmacklemsdcard_init(void) 351191783Srmacklem{ 352191783Srmacklem unsigned int tab_response[4]; 353191783Srmacklem#ifdef REPORT_SIZE 354191783Srmacklem unsigned int mult,blocknr; 355191783Srmacklem#endif 356191783Srmacklem int i; 357191783Srmacklem 358191783Srmacklem // Init MCI for MMC and SDCard interface 359191783Srmacklem AT91F_MCI_CfgPIO(); 360191783Srmacklem AT91F_MCI_CfgPMC(); 361191783Srmacklem AT91F_PDC_Open(AT91C_BASE_PDC_MCI); 362191783Srmacklem 363191783Srmacklem // Init Device Structure 364191783Srmacklem MCI_Device.state = AT91C_MCI_IDLE; 365191783Srmacklem MCI_Device.SDCard_bus_width = AT91C_MCI_SCDBUS; 366191783Srmacklem 367191783Srmacklem //* Reset the MCI 368191783Srmacklem AT91C_BASE_MCI->MCI_CR = AT91C_MCI_MCIEN | AT91C_MCI_PWSEN; 369191783Srmacklem AT91C_BASE_MCI->MCI_IDR = 0xFFFFFFFF; 370191783Srmacklem AT91C_BASE_MCI->MCI_DTOR = AT91C_MCI_DTOR_1MEGA_CYCLES; 371191783Srmacklem AT91C_BASE_MCI->MCI_MR = AT91C_MCI_PDCMODE; 372191783Srmacklem AT91C_BASE_MCI->MCI_SDCR = AT91C_MCI_SDCARD_4BITS_SLOTA; 373191783Srmacklem MCI_SendCommand(GO_IDLE_STATE_CMD, AT91C_NO_ARGUMENT); 374191783Srmacklem 375191783Srmacklem for (i = 0; i < 100; i++) { 376191783Srmacklem if (!MCI_SDCard_GetOCR(&MCI_Device)) 377191783Srmacklem break; 378191783Srmacklem printf("."); 379191783Srmacklem } 380191783Srmacklem if (i >= 100) 381191783Srmacklem return 0; 382191783Srmacklem if (MCI_SDCard_GetCID(tab_response)) 383191783Srmacklem return 0; 384191783Srmacklem if (MCI_SendCommand(SET_RELATIVE_ADDR_CMD, 0)) 385191783Srmacklem return 0; 386191783Srmacklem 387191783Srmacklem MCI_Device.RCA = (AT91C_BASE_MCI->MCI_RSPR[0] >> 16); 388191783Srmacklem if (MCI_GetCSD(MCI_Device.RCA,tab_response)) 389191783Srmacklem return 0; 390191783Srmacklem MCI_Device.READ_BL_LEN = (tab_response[1] >> CSD_1_RD_B_LEN_S) & 391191783Srmacklem CSD_1_RD_B_LEN_M; 392191783Srmacklem#ifdef REPORT_SIZE 393191783Srmacklem // compute MULT 394191783Srmacklem mult = 1 << ( ((tab_response[2] >> CSD_2_C_SIZE_M_S) & 395191783Srmacklem CSD_2_C_SIZE_M_M) + 2 ); 396191783Srmacklem // compute MSB of C_SIZE 397191783Srmacklem blocknr = ((tab_response[1] >> CSD_1_CSIZE_H_S) & 398191783Srmacklem CSD_1_CSIZE_H_M) << 2; 399191783Srmacklem // compute MULT * (LSB of C-SIZE + MSB already computed + 1) = BLOCKNR 400191783Srmacklem blocknr = mult * ((blocknr + ((tab_response[2] >> CSD_2_CSIZE_L_S) & 401191783Srmacklem CSD_2_CSIZE_L_M)) + 1); 402191783Srmacklem MCI_Device.Memory_Capacity = (1 << MCI_Device.READ_BL_LEN) * blocknr; 403191783Srmacklem#endif 404191783Srmacklem if (MCI_SDCard_SetBusWidth()) 405191783Srmacklem return 0; 406191783Srmacklem if (MCI_SendCommand(SET_BLOCKLEN_CMD, 1 << MCI_Device.READ_BL_LEN)) 407191783Srmacklem return 0; 408191783Srmacklem#ifdef REPORT_SIZE 409191783Srmacklem printf("Found SD card %u bytes\n", MCI_Device.Memory_Capacity); 410191783Srmacklem#endif 411191783Srmacklem return 1; 412191783Srmacklem} 413191783Srmacklem