Nut/OS  4.10.3
API Reference
spi_mmc.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2010 by egnite GmbH
00003  *
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * 1. Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer.
00012  * 2. Redistributions in binary form must reproduce the above copyright
00013  *    notice, this list of conditions and the following disclaimer in the
00014  *    documentation and/or other materials provided with the distribution.
00015  * 3. Neither the name of the copyright holders nor the names of
00016  *    contributors may be used to endorse or promote products derived
00017  *    from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00020  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00021  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00022  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00023  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00024  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00025  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00026  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00027  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00028  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00029  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00030  * SUCH DAMAGE.
00031  *
00032  * For additional information see http://www.ethernut.de/
00033  */
00034 
00049 #include <cfg/mmci.h>
00050 #include <sys/nutdebug.h>
00051 
00052 #if 0
00053 /* Use for local debugging. */
00054 #define NUTDEBUG
00055 #include <stdio.h>
00056 #endif
00057 
00058 #include <errno.h>
00059 #include <string.h>
00060 #include <stdlib.h>
00061 #include <memdebug.h>
00062 
00063 #include <sys/heap.h>
00064 #include <sys/timer.h>
00065 #include <sys/event.h>
00066 #include <fs/dospart.h>
00067 #include <fs/fs.h>
00068 
00069 #include <dev/blockdev.h>
00070 #include <dev/spibus.h>
00071 #include <dev/mmcard.h>
00072 
00077 
00078 #ifndef MMC_BLOCK_SIZE
00079 
00085 #define MMC_BLOCK_SIZE          512
00086 #endif
00087 
00088 #ifndef MMC_MAX_INIT_POLLS
00089 
00096 #define MMC_MAX_INIT_POLLS      512
00097 #endif
00098 
00099 #ifndef MMC_MAX_RESET_RETRIES
00100 
00105 #define MMC_MAX_RESET_RETRIES   2
00106 #endif
00107 
00108 #ifndef MMC_MAX_WRITE_RETRIES
00109 
00114 #define MMC_MAX_WRITE_RETRIES   2
00115 #endif
00116 
00117 #ifndef MMC_MAX_READ_RETRIES
00118 
00123 #define MMC_MAX_READ_RETRIES    MMC_MAX_WRITE_RETRIES
00124 #endif
00125 
00126 #ifndef MMC_MAX_CMDACK_POLLS
00127 
00134 #define MMC_MAX_CMDACK_POLLS    1024
00135 #endif
00136 
00137 #ifndef MMC_MAX_READY_POLLS
00138 
00145 #define MMC_MAX_READY_POLLS     800
00146 #endif
00147 
00148 
00149 /* HACK!!!
00150    Some SPI hardware just shift around data read from MISO pin to the MOSI pin if the SPI data register 
00151    is not set manually. At least on the AT91 platform it is impossible to use DMA transfers just for reading  
00152    and to hold the MOSI line at high level if no tx data is send out at the same time. So we declare a buffer   
00153    filled with 0xFF here, to make sure the MOSI pin is held at high level (0xFF) all the time during a 
00154    read only transfer. This buffer is used in CardRXData and several other places too. The buffer is read only.
00155 
00156    This is a very very nasty hack and waists 512 Bytes of ram, but I don't see a better solution right now!
00157 */
00158 
00159 static uint8_t dummy_tx_buf[MMC_BLOCK_SIZE];
00160 
00164 typedef struct _MMCFCB {
00167     NUTDEVICE *fcb_fsdev;
00168 
00171     DOSPART fcb_part;
00172 
00180     uint32_t fcb_address;
00181 
00191     uint8_t fcb_blkbuf[MMC_BLOCK_SIZE];
00192 } MMCFCB;
00193 
00194 #ifdef NUTDEBUG
00195 static void DumpData(uint8_t *buf, size_t len)
00196 {
00197     int i;
00198     int j;
00199 
00200     for (i = 0; i < len; i += 16) {
00201         printf("\n%03x ", i);
00202         for (j = 0; j < 16; j++) {
00203             if (i + j < len) {
00204                 printf("%02x ", buf[i + j]);
00205             } else {
00206                 printf("   ");
00207             }
00208         }
00209         for (j = 0; j < 16; j++) {
00210             if (i + j < len) {
00211                 if (buf[i + j] >= 32 && buf[i + j] < 127) {
00212                     putchar(buf[i + j]);
00213                 } else {
00214                     putchar('.');
00215                 }
00216             } else {
00217                 break;
00218             }
00219         }
00220     }
00221     putchar('\n');
00222 }
00223 #endif
00224 
00232 static int CardWaitRdy(NUTSPINODE * node)
00233 {
00234     int poll = MMC_MAX_READY_POLLS;
00235     uint8_t b;
00236     NUTSPIBUS *bus = (NUTSPIBUS *) node->node_bus;
00237 
00238     do {
00239         (*bus->bus_transfer) (node, dummy_tx_buf, &b, 1);
00240         if (b == 0xFF) {
00241             return 0;
00242         }
00243 #ifdef NUTDEBUG
00244         putchar('b');
00245 #endif
00246         if (poll < MMC_MAX_READY_POLLS / 4) {
00247             NutSleep(1);
00248         }
00249     } while (poll--);
00250 
00251     return -1;
00252 }
00253 
00261 static uint8_t CardRxTkn(NUTSPINODE * node)
00262 {
00263     uint8_t rc;
00264 
00265     int poll = MMC_MAX_CMDACK_POLLS;
00266     NUTSPIBUS *bus = (NUTSPIBUS *) node->node_bus;
00267 
00268     do {
00269         (*bus->bus_transfer) (node, dummy_tx_buf, &rc, 1);
00270         if (rc != 0xFF) {
00271             break;
00272         }
00273 #ifdef NUTDEBUG
00274         putchar('w');
00275 #endif
00276         if (poll < 3 * MMC_MAX_CMDACK_POLLS / 4) {
00277             NutSleep(1);
00278         }
00279     } while (poll--);
00280 #ifdef NUTDEBUG
00281     printf("[R%02x]", rc);
00282 #endif
00283 
00284     return rc;
00285 }
00286 
00308 static uint16_t CardTxCommand(NUTSPINODE * node, uint8_t cmd, uint32_t param, int len)
00309 {
00310     uint16_t rc = 0xFFFF;
00311     int retries = 4;
00312     uint8_t txb[7];
00313     uint8_t rxb;
00314     NUTSPIBUS *bus;
00315 
00316     bus = (NUTSPIBUS *) node->node_bus;
00317 
00318     /* Send command and parameter. */
00319     txb[0] = 0xFF;
00320     txb[1] = MMCMD_HOST | cmd;
00321     txb[2] = (uint8_t) (param >> 24);
00322     txb[3] = (uint8_t) (param >> 16);
00323     txb[4] = (uint8_t) (param >> 8);
00324     txb[5] = (uint8_t) param;
00325     /* We are running with CRC disabled. However, the reset command must
00326     ** be send with a valid CRC. Fortunately this command is sent with a
00327     ** fixed parameter value of zero, which results in a fixed CRC value. */
00328     txb[6] = MMCMD_RESET_CRC;
00329 
00330     while (rc == 0xFFFF && retries--) {
00331         if ((*bus->bus_alloc) (node, 1000)) {
00332             break;
00333         }
00334         if (CardWaitRdy(node) == 0) {
00335 #ifdef NUTDEBUG
00336             printf("\n[CMD%u,%lu]", cmd, param);
00337 #endif
00338             (*bus->bus_transfer) (node, txb, NULL, sizeof(txb));
00339             rxb = CardRxTkn(node);
00340             if (rxb != 0xFF) {
00341                 rc = rxb;
00342                 if (len == 0) {
00343                     break;
00344                 }
00345                 if (len == 2) {
00346                     (*bus->bus_transfer) (node, dummy_tx_buf, &rxb, 1);
00347                     rc <<= 8;
00348                     rc |= rxb;
00349                 }
00350             }
00351         }
00352         (*bus->bus_release) (node);
00353     }
00354     return rc;
00355 }
00356 
00367 static int CardInit(NUTSPINODE * node)
00368 {
00369     int i;
00370     int j;
00371     uint8_t rsp;
00372 
00373     /*
00374      * Switch to idle state and wait until initialization is running
00375      * or idle state is reached.
00376      */
00377     for (i = 0; i < MMC_MAX_RESET_RETRIES; i++) {
00378         rsp = CardTxCommand(node, MMCMD_GO_IDLE_STATE, 0, 1);
00379         for (j = 0; j < MMC_MAX_INIT_POLLS; j++) {
00380             rsp = CardTxCommand(node, MMCMD_SEND_OP_COND, 0, 1);
00381             if (rsp == MMR1_IDLE_STATE) {
00382                 return 0;
00383             }
00384             if (j > MMC_MAX_INIT_POLLS / 4) {
00385                 NutSleep(1);
00386             }
00387         }
00388     }
00389     return -1;
00390 }
00391 
00406 static int CardRxData(NUTSPINODE * node, uint8_t cmd, uint32_t param, uint8_t *buf, int len)
00407 {
00408     int rc = -1;
00409     uint8_t rsp;
00410     NUTSPIBUS *bus;
00411     int retries = MMC_MAX_READ_RETRIES;
00412 
00413 
00414     /* Sanity checks. */
00415     NUTASSERT(node != NULL);
00416     NUTASSERT(node->node_bus != NULL);
00417 
00418     bus = (NUTSPIBUS *) node->node_bus;
00419 
00420     while (rc && retries--) {
00421         rsp = (uint8_t)CardTxCommand(node, cmd, param, 0);
00422         if (rsp != 0xFF) {
00423             if (rsp == 0 && CardRxTkn(node) == 0xFE) {
00424                 /* Data transfer. */
00425                 (*bus->bus_transfer) (node, dummy_tx_buf, buf, len);
00426                 /* Ignore the CRC. */
00427                 (*bus->bus_transfer) (node, dummy_tx_buf, NULL, 2);
00428                 rc = 0;
00429             }
00430             (*bus->bus_release) (node);
00431         }
00432     }
00433     return rc;
00434 }
00435 
00450 static int CardTxData(NUTSPINODE * node, uint8_t cmd, uint32_t param, CONST uint8_t *buf, int len)
00451 {
00452     int rc = -1;
00453     uint8_t rsp;
00454     NUTSPIBUS *bus;
00455     int retries = MMC_MAX_WRITE_RETRIES;
00456 
00457     /* Sanity checks. */
00458     NUTASSERT(node != NULL);
00459     NUTASSERT(node->node_bus != NULL);
00460 
00461     bus = (NUTSPIBUS *) node->node_bus;
00462     while (rc && retries--) {
00463         rsp = (uint8_t)CardTxCommand(node, cmd, param, 0);
00464         if (rsp != 0xFF) {
00465             if (rsp == 0) {
00466                 uint8_t tkn[2] = { 0xFF, 0xFE };
00467 
00468                 /* Send start token. */
00469                 (*bus->bus_transfer) (node, &tkn, NULL, sizeof(tkn));
00470                 /* Data transfer. */
00471                 (*bus->bus_transfer) (node, buf, NULL, len);
00472                 /* Send dummy CRC. */
00473                 (*bus->bus_transfer) (node, dummy_tx_buf, NULL, 2);
00474                 /* Get response. */
00475                 if (CardRxTkn(node) == 0xE5) {
00476                     rc = 0;
00477                 }
00478             }
00479             (*bus->bus_release) (node);
00480         }
00481     }
00482     return rc;
00483 }
00484 
00500 int SpiMmcBlockRead(NUTFILE * nfp, void *buffer, int num)
00501 {
00502     MMCFCB *fcb;
00503     NUTDEVICE *dev;
00504     MEMCARDSUPP *msc;
00505 
00506     /* Sanity checks. */
00507     NUTASSERT(nfp != NULL);
00508     NUTASSERT(nfp->nf_fcb != NULL);
00509     NUTASSERT(nfp->nf_dev != NULL);
00510     fcb = (MMCFCB *) nfp->nf_fcb;
00511     dev = (NUTDEVICE *) nfp->nf_dev;
00512     NUTASSERT(dev->dev_dcb != NULL);
00513     msc = (MEMCARDSUPP *) dev->dev_dcb;
00514 
00515     /* Make sure there was no card change. */
00516     if (msc->mcs_cf == 0) {
00517         /* Activate the write indicator. */
00518         msc->mcs_act(NUTMC_IND_READ);
00519         /* Use the internal buffer if none is provided. */
00520         if (buffer == NULL) {
00521             buffer = fcb->fcb_blkbuf;
00522         }
00523         /* Transfer the data from the card. */
00524         if (CardRxData(dev->dev_icb, MMCMD_READ_SINGLE_BLOCK, fcb->fcb_address, buffer, MMC_BLOCK_SIZE) == 0) {
00525             /* Deactivate the indicator. */
00526             msc->mcs_act(NUTMC_IND_OFF);
00527 #ifdef NUTDEBUG
00528             DumpData(buffer, MMC_BLOCK_SIZE);
00529 #endif
00530             return 1;
00531         }
00532     }
00533     /* Activate the error indicator. */
00534     msc->mcs_act(NUTMC_IND_ERROR);
00535     return -1;
00536 }
00537 
00553 int SpiMmcBlockWrite(NUTFILE * nfp, CONST void *buffer, int num)
00554 {
00555     MMCFCB *fcb;
00556     NUTDEVICE *dev;
00557     MEMCARDSUPP *msc;
00558 
00559     /* Sanity checks. */
00560     NUTASSERT(nfp != NULL);
00561     NUTASSERT(nfp->nf_fcb != NULL);
00562     NUTASSERT(nfp->nf_dev != NULL);
00563     fcb = (MMCFCB *) nfp->nf_fcb;
00564     dev = (NUTDEVICE *) nfp->nf_dev;
00565     NUTASSERT(dev->dev_dcb != NULL);
00566     msc = (MEMCARDSUPP *) dev->dev_dcb;
00567 
00568     /* Make sure there was no card change. */
00569     if (msc->mcs_cf == 0) {
00570         /* Activate the write indicator. */
00571         msc->mcs_act(NUTMC_IND_WRITE);
00572         /* Use the internal buffer if none is provided. */
00573         if (buffer == NULL) {
00574             buffer = fcb->fcb_blkbuf;
00575         }
00576         /* Transfer the data to the card. */
00577         if (CardTxData(dev->dev_icb, MMCMD_WRITE_BLOCK, fcb->fcb_address, buffer, MMC_BLOCK_SIZE) == 0) {
00578             /* Deactivate the indicator. */
00579             msc->mcs_act(NUTMC_IND_OFF);
00580             return 1;
00581         }
00582     }
00583     /* Activate the error indicator. */
00584     msc->mcs_act(NUTMC_IND_ERROR);
00585     return -1;
00586 }
00587 
00588 #ifdef __HARVARD_ARCH__
00589 
00608 int SpiMmcBlockWrite_P(NUTFILE * nfp, PGM_P buffer, int num)
00609 {
00610     return -1;
00611 }
00612 #endif
00613 
00614 int SpiMmcUnmount(NUTFILE * nfp);
00615 
00641 NUTFILE *SpiMmcMount(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00642 {
00643     int partno = 0;
00644     int i;
00645     NUTDEVICE *fsdev;
00646     NUTFILE *nfp;
00647     MMCFCB *fcb;
00648     DOSPART *part;
00649     MEMCARDSUPP *msc = (MEMCARDSUPP *) dev->dev_dcb;
00650     FSCP_VOL_MOUNT mparm;
00651     NUTSPINODE * node = (NUTSPINODE *) dev->dev_icb;
00652 
00653     /* Return an error if no card is detected. */
00654     if ((msc->mcs_sf & NUTMC_SF_CD) == 0) {
00655         errno = ENODEV;
00656         return NUTFILE_EOF;
00657     }
00658     /* Clear the card change flag. */
00659     msc->mcs_cf = 0;
00660 
00661     /* Set the card in SPI mode. */
00662     if (CardInit(node)) {
00663         errno = ENODEV;
00664         return NUTFILE_EOF;
00665     }
00666 
00667     /* Parse the name for a partition number and a file system driver. */
00668     if (*name) {
00669         partno = atoi(name);
00670         do {
00671             name++;
00672         } while (*name && *name != '/');
00673         if (*name == '/') {
00674             name++;
00675         }
00676     }
00677 
00678     /*
00679      * Check the list of registered devices for the given name of the
00680      * files system driver. If none has been specified, get the first
00681      * file system driver in the list. Hopefully the application
00682      * registered one only.
00683      */
00684     for (fsdev = nutDeviceList; fsdev; fsdev = fsdev->dev_next) {
00685         if (*name == 0) {
00686             if (fsdev->dev_type == IFTYP_FS) {
00687                 break;
00688             }
00689         } else if (strcmp(fsdev->dev_name, name) == 0) {
00690             break;
00691         }
00692     }
00693 
00694     if (fsdev == 0) {
00695 #ifdef NUTDEBUG
00696         printf("[NoFS'%s]", name);
00697 #endif
00698         errno = ENODEV;
00699         return NUTFILE_EOF;
00700     }
00701 
00702     if ((fcb = calloc(1, sizeof(MMCFCB))) == 0) {
00703         errno = ENOMEM;
00704         return NUTFILE_EOF;
00705     }
00706     fcb->fcb_fsdev = fsdev;
00707 
00708     /* Read MBR. */
00709     if (CardRxData(node, MMCMD_READ_SINGLE_BLOCK, 0, fcb->fcb_blkbuf, MMC_BLOCK_SIZE)) {
00710         free(fcb);
00711         return NUTFILE_EOF;
00712     }
00713 #ifdef NUTDEBUG
00714     DumpData(fcb->fcb_blkbuf, MMC_BLOCK_SIZE);
00715 #endif
00716     /* Check for the cookie at the end of this sector. */
00717         if (fcb->fcb_blkbuf[DOSPART_MAGICPOS] != 0x55 || fcb->fcb_blkbuf[DOSPART_MAGICPOS + 1] != 0xAA) {
00718         free(fcb);
00719         return NUTFILE_EOF;
00720         }
00721     /* Check for the partition table. */
00722         if(fcb->fcb_blkbuf[DOSPART_TYPEPOS] == 'F' && 
00723        fcb->fcb_blkbuf[DOSPART_TYPEPOS + 1] == 'A' &&
00724        fcb->fcb_blkbuf[DOSPART_TYPEPOS + 2] == 'T') {
00725         /* No partition table. Assume FAT12 and 32MB size. */
00726         fcb->fcb_part.part_type = PTYPE_FAT12;
00727         fcb->fcb_part.part_sect_offs = 0;
00728         fcb->fcb_part.part_sects = 65536; /* How to find out? */
00729         }
00730     else {
00731         /* Read partition table. */
00732         part = (DOSPART *) & fcb->fcb_blkbuf[DOSPART_SECTORPOS];
00733 #ifdef NUTDEBUG
00734         for (i = 0; i < 4; i++) {
00735             printf("- State 0x%02x\n", part[i].part_state);
00736             printf("  Type  0x%02x\n", part[i].part_type);
00737             printf("  Start %lu\n", part[i].part_sect_offs);
00738             printf("  Size  %lu\n", part[i].part_sects);
00739         }
00740 #endif
00741         for (i = 1; i <= 4; i++) {
00742             if (partno) {
00743                 if (i == partno) {
00744                     /* Found specified partition number. */
00745                     fcb->fcb_part = *part;
00746                     break;
00747                 }
00748             } else if (part->part_state & 0x80) {
00749                 /* Located first active partition. */
00750                 fcb->fcb_part = *part;
00751                 break;
00752             }
00753             part++;
00754         }
00755 
00756         if (fcb->fcb_part.part_type == PTYPE_EMPTY) {
00757             free(fcb);
00758             return NUTFILE_EOF;
00759         }
00760     }
00761 
00762     if ((nfp = NutHeapAlloc(sizeof(NUTFILE))) == 0) {
00763         free(fcb);
00764         errno = ENOMEM;
00765         return NUTFILE_EOF;
00766     }
00767     nfp->nf_next = 0;
00768     nfp->nf_dev = dev;
00769     nfp->nf_fcb = fcb;
00770 
00771     /*
00772      * Mount the file system volume.
00773      */
00774     mparm.fscp_bmnt = nfp;
00775     mparm.fscp_part_type = fcb->fcb_part.part_type;
00776     if (fsdev->dev_ioctl(fsdev, FS_VOL_MOUNT, &mparm)) {
00777         SpiMmcUnmount(nfp);
00778         return NUTFILE_EOF;
00779     }
00780     return nfp;
00781 }
00782 
00793 int SpiMmcUnmount(NUTFILE * nfp)
00794 {
00795     int rc;
00796     MMCFCB *fcb;
00797 
00798     /* Sanity checks. */
00799     NUTASSERT(nfp != NULL);
00800     NUTASSERT(nfp->nf_fcb != NULL);
00801     fcb = (MMCFCB *) nfp->nf_fcb;
00802 
00803     /* Intentionally we do not check the card change flag here to allow the
00804     ** file system to release all claimed resources. */
00805     rc = fcb->fcb_fsdev->dev_ioctl(fcb->fcb_fsdev, FS_VOL_UNMOUNT, NULL);
00806     free(fcb);
00807     free(nfp);
00808 
00809     return rc;
00810 }
00811 
00835 int SpiMmcIOCtl(NUTDEVICE * dev, int req, void *conf)
00836 {
00837     int rc = 0;
00838     NUTSPINODE * node = (NUTSPINODE *) dev->dev_icb;
00839     MEMCARDSUPP *msc = (MEMCARDSUPP *) dev->dev_dcb;
00840 
00841     switch (req) {
00842     case NUTBLKDEV_MEDIAAVAIL:
00843         {
00844             int *flg = (int *) conf;
00845             *flg = msc->mcs_sf & NUTMC_SF_CD;
00846         }
00847         break;
00848     case NUTBLKDEV_MEDIACHANGE:
00849         {
00850             int *flg = (int *) conf;
00851             *flg = msc->mcs_cf;
00852         }
00853         break;
00854     case NUTBLKDEV_INFO:
00855         {
00856             BLKPAR_INFO *par = (BLKPAR_INFO *) conf;
00857             MMCFCB *fcb = (MMCFCB *) par->par_nfp->nf_fcb;
00858 
00859             par->par_nblks = fcb->fcb_part.part_sects;
00860             par->par_blksz = MMC_BLOCK_SIZE;
00861             par->par_blkbp = fcb->fcb_blkbuf;
00862         }
00863         break;
00864     case NUTBLKDEV_SEEK:
00865         {
00866             BLKPAR_SEEK *par = (BLKPAR_SEEK *) conf;
00867             MMCFCB *fcb = (MMCFCB *) par->par_nfp->nf_fcb;
00868 
00869             /* Caclaulate the byte offset. */
00870             fcb->fcb_address = (par->par_blknum + fcb->fcb_part.part_sect_offs) << 9;
00871         }
00872         break;
00873     case MMCARD_GETSTATUS:
00874         {
00875             uint16_t *s = (uint16_t *) conf;
00876 
00877             *s = CardTxCommand(node, MMCMD_SEND_STATUS, 0, 2);
00878         }
00879         break;
00880     case MMCARD_GETOCR:
00881         {
00882             NUTSPIBUS *bus = (NUTSPIBUS *) node->node_bus;
00883 
00884             if (CardTxCommand(node, MMCMD_READ_OCR, 0, 0) == MMR1_IDLE_STATE) {
00885                 uint32_t * ocr = (uint32_t *) conf;
00886                 uint_fast8_t i;
00887                 uint8_t rxb;
00888 
00889                 for (i = 0; i < 4; i++) {
00890                     (*bus->bus_transfer) (node, dummy_tx_buf, &rxb, 1);
00891                     *ocr <<= 8;
00892                     *ocr |= rxb;
00893                 }
00894 
00895             } else {
00896                 rc = 1;
00897             }
00898             (*bus->bus_release) (node);
00899         }
00900         break;
00901     case MMCARD_GETCID:
00902         rc = CardRxData(node, MMCMD_SEND_CID, 0, (uint8_t *) conf, sizeof(MMC_CID));
00903         break;
00904     case MMCARD_GETCSD:
00905         rc = CardRxData(node, MMCMD_SEND_CSD, 0, (uint8_t *) conf, sizeof(MMC_CSD));
00906         break;
00907     case MMCARD_GETEXTCSD:
00908         rc = CardRxData(node, MMCMD_SEND_EXTCSD, 0, (uint8_t *) conf, sizeof(MMC_CSD));
00909         break;
00910     default:
00911         rc = -1;
00912         break;
00913     }
00914     return rc;
00915 }
00916 
00928 int SpiMmcInit(NUTDEVICE * dev)
00929 {
00930     memset(dummy_tx_buf, 0xFF, MMC_BLOCK_SIZE);
00931     return 0;
00932 }
00933