Nut/OS  4.10.3
API Reference
mmcard.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2005-2007 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  */
00032 
00098 #include <cfg/mmci.h>
00099 
00100 #if 0
00101 /* Use for local debugging. */
00102 #define NUTDEBUG
00103 #include <stdio.h>
00104 #endif
00105 
00106 #include <errno.h>
00107 #include <string.h>
00108 #include <stdlib.h>
00109 #include <memdebug.h>
00110 
00111 #include <sys/heap.h>
00112 #include <sys/timer.h>
00113 #include <sys/event.h>
00114 #include <fs/dospart.h>
00115 #include <fs/fs.h>
00116 
00117 #include <dev/blockdev.h>
00118 #include <dev/mmcard.h>
00119 
00124 
00125 #ifndef MMC_BLOCK_SIZE
00126 
00132 #define MMC_BLOCK_SIZE          512
00133 #endif
00134 
00135 #ifndef MMC_MAX_INIT_POLLS
00136 
00143 #define MMC_MAX_INIT_POLLS      512
00144 #endif
00145 
00146 #ifndef MMC_MAX_RESET_POLLS
00147 
00152 #define MMC_MAX_RESET_POLLS     255
00153 #endif
00154 
00155 #ifndef MMC_MAX_WRITE_POLLS
00156 
00163 #define MMC_MAX_WRITE_POLLS     1024
00164 #endif
00165 
00166 #ifndef MMC_MAX_WRITE_RETRIES
00167 
00172 #define MMC_MAX_WRITE_RETRIES   32
00173 #endif
00174 
00175 #ifndef MMC_MAX_READ_RETRIES
00176 
00181 #define MMC_MAX_READ_RETRIES    8
00182 #endif
00183 
00184 #ifndef MMC_MAX_REG_POLLS
00185 
00190 #define MMC_MAX_REG_POLLS       512
00191 #endif
00192 
00193 #ifndef MMC_MAX_CMDACK_POLLS
00194 
00201 #define MMC_MAX_CMDACK_POLLS    1024
00202 #endif
00203 
00204 #ifndef MMC_MAX_R1_POLLS
00205 
00210 #define MMC_MAX_R1_POLLS        1024
00211 #endif
00212 
00216 typedef struct _MMCFCB {
00219     NUTDEVICE *fcb_fsdev;
00220 
00223     DOSPART fcb_part;
00224 
00232     uint32_t fcb_blknum;
00233 
00243     uint8_t fcb_blkbuf[MMC_BLOCK_SIZE];
00244 } MMCFCB;
00245 
00246 /*
00247  * Several routines call NutSleep, which results in a context switch.
00248  * This mutual exclusion semaphore takes care, that multiple threads
00249  * do not interfere with each other.
00250  */
00251 static HANDLE mutex;
00252 
00260 static void MmCardTxCmd(MMCIFC * ifc, uint8_t cmd, uint32_t param)
00261 {
00262     unsigned int tmo = MMC_MAX_CMDACK_POLLS;
00263     uint8_t ch;
00264 
00265     /* Enable card select. */
00266     (*ifc->mmcifc_cs) (1);
00267     /*
00268      * Repeat sending nothing until we receive nothing. Actually
00269      * it should be sufficient to send a single 0xFF value, but
00270      * running a loop seems to fix certain kind of sync problems.
00271      */
00272     while ((ch = (*ifc->mmcifc_io) (0xFF)) != 0xFF) {
00273         if (--tmo == 0) {
00274 #ifdef NUTDEBUG
00275             printf("[MMCmd%u Timeout %02X]\n", cmd, ch);
00276 #endif
00277             break;
00278         }
00279         if (tmo < MMC_MAX_CMDACK_POLLS / 4) {
00280             NutSleep(1);
00281         }
00282     }
00283     /* Send command and parameter. */
00284     (*ifc->mmcifc_io) (MMCMD_HOST | cmd);
00285     (*ifc->mmcifc_io) ((uint8_t) (param >> 24));
00286     (*ifc->mmcifc_io) ((uint8_t) (param >> 16));
00287     (*ifc->mmcifc_io) ((uint8_t) (param >> 8));
00288     (*ifc->mmcifc_io) ((uint8_t) param);
00289     /*
00290      * We are running with CRC disabled. However, the reset command must
00291      * be send with a valid CRC. Fortunately this command is sent with a
00292      * fixed parameter value of zero, which results in a fixed CRC value
00293      */
00294     (*ifc->mmcifc_io) (MMCMD_RESET_CRC);
00295 }
00296 
00307 static uint8_t MmCardRxR1(MMCIFC * ifc)
00308 {
00309     uint8_t rc;
00310     int i;
00311 
00312     for (i = 0; i < MMC_MAX_R1_POLLS; i++) {
00313         if ((rc = (*ifc->mmcifc_io) (0xFF)) != 0xFF) {
00314             break;
00315         }
00316     }
00317     return rc;
00318 }
00319 
00330 static uint16_t MmCardRxR2(MMCIFC * ifc)
00331 {
00332     uint16_t rc;
00333 
00334     rc = MmCardRxR1(ifc);
00335     rc <<= 8;
00336     rc += (*ifc->mmcifc_io) (0xFF);
00337 
00338     return rc;
00339 }
00340 
00352 static uint8_t MmCardRxR3(MMCIFC * ifc, uint32_t * ocr)
00353 {
00354     uint8_t rc;
00355     int i;
00356 
00357     /* The first byte is equal to the R1 response. */
00358     rc = MmCardRxR1(ifc);
00359     /* Receive the operating condition. */
00360     for (i = 0; i < 4; i++) {
00361         *ocr <<= 8;
00362         *ocr |= (*ifc->mmcifc_io) (0xFF);
00363     }
00364     return rc;
00365 }
00366 
00374 static int MmCardReset(MMCIFC * ifc)
00375 {
00376     int i;
00377     uint8_t rsp;
00378 
00379     /*
00380      * Initialize the low level card interface.
00381      */
00382     if ((*ifc->mmcifc_in) ()) {
00383         return -1;
00384     }
00385 
00386     /*
00387      * 80 bits of ones with deactivated chip select will put the card 
00388      * in SPI mode.
00389      */
00390     (*ifc->mmcifc_cs) (0);
00391     for (i = 0; i < 10; i++) {
00392         (*ifc->mmcifc_io) (0xFF);
00393     }
00394 
00395     /*
00396      * Switch to idle state and wait until initialization is running
00397      * or idle state is reached.
00398      */
00399     for (i = 0; i < MMC_MAX_RESET_POLLS; i++) {
00400         MmCardTxCmd(ifc, MMCMD_GO_IDLE_STATE, 0);
00401         rsp = MmCardRxR1(ifc);
00402         (*ifc->mmcifc_cs) (0);
00403         if (rsp == MMR1_IDLE_STATE || rsp == MMR1_NOT_IDLE) {
00404             return 0;
00405         }
00406     }
00407     return -1;
00408 }
00409 
00420 static int MmCardInit(MMCIFC * ifc)
00421 {
00422     int i;
00423     uint8_t rsp;
00424 
00425     /*
00426      * Try to switch to SPI mode. Looks like a retry helps to fix
00427      * certain synchronization problems.
00428      */
00429     if (MmCardReset(ifc)) {
00430         if (MmCardReset(ifc)) {
00431 #ifdef NUTDEBUG
00432             printf("[CardReset failed]");
00433 #endif
00434             return -1;
00435         }
00436     }
00437 
00438     /*
00439      * Wait for a really long time until card is initialized
00440      * and enters idle state.
00441      */
00442     for (i = 0; i < MMC_MAX_INIT_POLLS; i++) {
00443         /*
00444          * In SPI mode SEND_OP_COND is a dummy, used to poll the card
00445          * for initialization finished. Thus, there are no parameters
00446          * and no operation condition data is sent back.
00447          */
00448         MmCardTxCmd(ifc, MMCMD_SEND_OP_COND, 0);
00449         rsp = MmCardRxR1(ifc);
00450         (*ifc->mmcifc_cs) (0);
00451         if (rsp == MMR1_IDLE_STATE) {
00452 #ifdef NUTDEBUG
00453             printf("[CardIdle]");
00454 #endif
00455             /* Initialize MMC access mutex semaphore. */
00456             NutEventPost(&mutex);
00457             return 0;
00458         }
00459         if (i > MMC_MAX_INIT_POLLS / 4) {
00460             NutSleep(1);
00461         }
00462     }
00463 #ifdef NUTDEBUG
00464     printf("[CardInit failed]");
00465 #endif
00466     return -1;
00467 }
00468 
00479 static int MmCardReadOrVerify(MMCIFC * ifc, uint32_t blk, uint8_t * buf, int vflg)
00480 {
00481     int rc = -1;
00482     int retries = 64;
00483     int i;
00484     uint8_t rsp;
00485 
00486     /* Gain mutex access. */
00487     NutEventWait(&mutex, 0);
00488 
00489     while (retries--) {
00490         MmCardTxCmd(ifc, MMCMD_READ_SINGLE_BLOCK, blk << 9);
00491         if ((rsp = MmCardRxR1(ifc)) == 0x00) {
00492             if ((rsp = MmCardRxR1(ifc)) == 0xFE) {
00493                 rc = 0;
00494                 if (vflg) {
00495                     for (i = 0; i < MMC_BLOCK_SIZE; i++) {
00496                         if (*buf != (*ifc->mmcifc_io) (0xFF)) {
00497                             rc = -1;
00498                         }
00499                         buf++;
00500                     }
00501                 } else {
00502                     for (i = 0; i < MMC_BLOCK_SIZE; i++) {
00503                         *buf = (*ifc->mmcifc_io) (0xFF);
00504                         buf++;
00505                     }
00506                 }
00507                 (*ifc->mmcifc_io) (0xff);
00508                 (*ifc->mmcifc_io) (0xff);
00509                 (*ifc->mmcifc_cs) (0);
00510                 break;
00511             }
00512         }
00513         (*ifc->mmcifc_cs) (0);
00514     }
00515 
00516     /* Release mutex access. */
00517     NutEventPost(&mutex);
00518 
00519     return rc;
00520 }
00521 
00531 static int MmCardWrite(MMCIFC * ifc, uint32_t blk, CONST uint8_t * buf)
00532 {
00533     int rc = -1;
00534     int retries = MMC_MAX_WRITE_RETRIES;
00535     int tmo;
00536     int i;
00537     uint8_t rsp;
00538 
00539     /* Gain mutex access. */
00540     NutEventWait(&mutex, 0);
00541 
00542     while (retries--) {
00543         MmCardTxCmd(ifc, MMCMD_WRITE_BLOCK, blk << 9);
00544         if ((rsp = MmCardRxR1(ifc)) == 0x00) {
00545             (*ifc->mmcifc_io) (0xFF);
00546             (*ifc->mmcifc_io) (0xFE);
00547             for (i = 0; i < MMC_BLOCK_SIZE; i++) {
00548                 (*ifc->mmcifc_io) (*buf);
00549                 buf++;
00550             }
00551             // (*ifc->mmcifc_io)(0xFF);
00552             // (*ifc->mmcifc_io)(0xFF);
00553             if ((rsp = MmCardRxR1(ifc)) == 0xE5) {
00554                 for (tmo = 0; tmo < MMC_MAX_WRITE_POLLS; tmo++) {
00555                     if ((*ifc->mmcifc_io) (0xFF) == 0xFF) {
00556                         break;
00557                     }
00558                     if (tmo > MMC_MAX_WRITE_POLLS - MMC_MAX_WRITE_POLLS / 32) {
00559                         NutSleep(1);
00560                     }
00561                 }
00562                 if (tmo) {
00563                     rc = 0;
00564                     break;
00565                 }
00566 #ifdef NUTDEBUG
00567                 printf("[MMCWR Timeout]\n");
00568 #endif
00569             }
00570         }
00571         (*ifc->mmcifc_cs) (0);
00572     }
00573     (*ifc->mmcifc_cs) (0);
00574 
00575     /* Release mutex access. */
00576     NutEventPost(&mutex);
00577 
00578     return rc;
00579 }
00580 
00596 int MmCardBlockRead(NUTFILE * nfp, void *buffer, int num)
00597 {
00598     MMCFCB *fcb = (MMCFCB *) nfp->nf_fcb;
00599     uint32_t blk = fcb->fcb_blknum;
00600     NUTDEVICE *dev = (NUTDEVICE *) nfp->nf_dev;
00601     MMCIFC *ifc = (MMCIFC *) dev->dev_icb;
00602 
00603     if ((*ifc->mmcifc_cd) () != 1) {
00604         return -1;
00605     }
00606     if (buffer == 0) {
00607         buffer = fcb->fcb_blkbuf;
00608     }
00609     blk += fcb->fcb_part.part_sect_offs;
00610 
00611 #ifdef MMC_VERIFY_AFTER
00612     {
00613         int i;
00614         /*
00615          * It would be much better to verify the checksum than to re-read
00616          * and verify the data block.
00617          */
00618         for (i = 0; i < MMC_MAX_READ_RETRIES; i++) {
00619             if (MmCardReadOrVerify(ifc, blk, buffer, 0) == 0) {
00620                 if (MmCardReadOrVerify(ifc, blk, buffer, 1) == 0) {
00621                     return 1;
00622                 }
00623             }
00624         }
00625     }
00626 #else
00627     if (MmCardReadOrVerify(ifc, blk, buffer, 0) == 0) {
00628         return 1;
00629     }
00630 #endif
00631     return -1;
00632 }
00633 
00649 int MmCardBlockWrite(NUTFILE * nfp, CONST void *buffer, int num)
00650 {
00651     MMCFCB *fcb = (MMCFCB *) nfp->nf_fcb;
00652     uint32_t blk = fcb->fcb_blknum;
00653     NUTDEVICE *dev = (NUTDEVICE *) nfp->nf_dev;
00654     MMCIFC *ifc = (MMCIFC *) dev->dev_icb;
00655 
00656     if ((*ifc->mmcifc_cd) () != 1) {
00657         return -1;
00658     }
00659     if (buffer == 0) {
00660         buffer = fcb->fcb_blkbuf;
00661     }
00662     blk += fcb->fcb_part.part_sect_offs;
00663 
00664 #ifdef MMC_VERIFY_AFTER
00665     {
00666         int i;
00667 
00668         for (i = 0; i < MMC_MAX_READ_RETRIES; i++) {
00669             if (MmCardWrite(ifc, blk, buffer) == 0) {
00670                 if (MmCardReadOrVerify(ifc, blk, (void *) buffer, 1) == 0) {
00671                     return 1;
00672                 }
00673                 if (MmCardReadOrVerify(ifc, blk, (void *) buffer, 1) == 0) {
00674                     return 1;
00675                 }
00676             }
00677         }
00678     }
00679 #else
00680     if (MmCardWrite(ifc, blk, buffer) == 0) {
00681         return 1;
00682     }
00683 #endif
00684     return -1;
00685 }
00686 
00687 #ifdef __HARVARD_ARCH__
00688 
00707 int MmCardBlockWrite_P(NUTFILE * nfp, PGM_P buffer, int num)
00708 {
00709     return -1;
00710 }
00711 #endif
00712 
00738 NUTFILE *MmCardMount(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00739 {
00740     int partno = 0;
00741     int i;
00742     NUTDEVICE *fsdev;
00743     NUTFILE *nfp;
00744     MMCFCB *fcb;
00745     DOSPART *part;
00746     MMCIFC *ifc = (MMCIFC *) dev->dev_icb;
00747     FSCP_VOL_MOUNT mparm;
00748 
00749     /* Return an error if no card is detected. */
00750     if ((*ifc->mmcifc_cd) () == 0) {
00751         errno = ENODEV;
00752         return NUTFILE_EOF;
00753     }
00754 
00755     /* Set the card in SPI mode. */
00756     if (MmCardInit(ifc)) {
00757         errno = ENODEV;
00758         return NUTFILE_EOF;
00759     }
00760 
00761     /* Parse the name for a partition number and a file system driver. */
00762     if (*name) {
00763         partno = atoi(name);
00764         do {
00765             name++;
00766         } while (*name && *name != '/');
00767         if (*name == '/') {
00768             name++;
00769         }
00770     }
00771 
00772     /*
00773      * Check the list of registered devices for the given name of the
00774      * files system driver. If none has been specified, get the first
00775      * file system driver in the list. Hopefully the application
00776      * registered one only.
00777      */
00778     for (fsdev = nutDeviceList; fsdev; fsdev = fsdev->dev_next) {
00779         if (*name == 0) {
00780             if (fsdev->dev_type == IFTYP_FS) {
00781                 break;
00782             }
00783         } else if (strcmp(fsdev->dev_name, name) == 0) {
00784             break;
00785         }
00786     }
00787 
00788     if (fsdev == 0) {
00789 #ifdef NUTDEBUG
00790         printf("[No FSDriver]");
00791 #endif
00792         errno = ENODEV;
00793         return NUTFILE_EOF;
00794     }
00795 
00796     if ((fcb = calloc(1, sizeof(MMCFCB))) == 0) {
00797         errno = ENOMEM;
00798         return NUTFILE_EOF;
00799     }
00800     fcb->fcb_fsdev = fsdev;
00801 
00802     /* Read MBR. */
00803     if (MmCardReadOrVerify(ifc, 0, fcb->fcb_blkbuf, 0)) {
00804         free(fcb);
00805         return NUTFILE_EOF;
00806     }
00807     /* Check for the cookie at the end of this sector. */
00808         if (fcb->fcb_blkbuf[DOSPART_MAGICPOS] != 0x55 || fcb->fcb_blkbuf[DOSPART_MAGICPOS + 1] != 0xAA) {
00809         free(fcb);
00810         return NUTFILE_EOF;
00811         }
00812     /* Check for the partition table. */
00813         if(fcb->fcb_blkbuf[DOSPART_TYPEPOS] == 'F' && 
00814        fcb->fcb_blkbuf[DOSPART_TYPEPOS + 1] == 'A' &&
00815        fcb->fcb_blkbuf[DOSPART_TYPEPOS + 2] == 'T') {
00816         /* No partition table. Assume FAT12 and 32MB size. */
00817         fcb->fcb_part.part_type = PTYPE_FAT12;
00818         fcb->fcb_part.part_sect_offs = 0;
00819         fcb->fcb_part.part_sects = 65536; /* How to find out? */
00820         }
00821     else {
00822         /* Read partition table. */
00823         part = (DOSPART *) & fcb->fcb_blkbuf[DOSPART_SECTORPOS];
00824         for (i = 1; i <= 4; i++) {
00825             if (partno) {
00826                 if (i == partno) {
00827                     /* Found specified partition number. */
00828                     fcb->fcb_part = *part;
00829                     break;
00830                 }
00831             } else if (part->part_state & 0x80) {
00832                 /* Located first active partition. */
00833                 fcb->fcb_part = *part;
00834                 break;
00835             }
00836             part++;
00837         }
00838 
00839         if (fcb->fcb_part.part_type == PTYPE_EMPTY) {
00840             free(fcb);
00841             return NUTFILE_EOF;
00842         }
00843     }
00844 
00845     if ((nfp = NutHeapAlloc(sizeof(NUTFILE))) == 0) {
00846         free(fcb);
00847         errno = ENOMEM;
00848         return NUTFILE_EOF;
00849     }
00850     nfp->nf_next = 0;
00851     nfp->nf_dev = dev;
00852     nfp->nf_fcb = fcb;
00853 
00854     /*
00855      * Mount the file system volume.
00856      */
00857     mparm.fscp_bmnt = nfp;
00858     mparm.fscp_part_type = fcb->fcb_part.part_type;
00859     if (fsdev->dev_ioctl(fsdev, FS_VOL_MOUNT, &mparm)) {
00860         MmCardUnmount(nfp);
00861         return NUTFILE_EOF;
00862     }
00863     return nfp;
00864 }
00865 
00874 int MmCardUnmount(NUTFILE * nfp)
00875 {
00876     int rc = -1;
00877 
00878     if (nfp) {
00879         MMCFCB *fcb = (MMCFCB *) nfp->nf_fcb;
00880 
00881         if (fcb) {
00882             NUTDEVICE *dev = (NUTDEVICE *) nfp->nf_dev;
00883             MMCIFC *ifc = (MMCIFC *) dev->dev_icb;
00884 
00885             if ((*ifc->mmcifc_cd) () == 1) {
00886                 rc = fcb->fcb_fsdev->dev_ioctl(fcb->fcb_fsdev, FS_VOL_UNMOUNT, NULL);
00887             }
00888             free(fcb);
00889         }
00890         free(nfp);
00891     }
00892     return rc;
00893 }
00894 
00906 static int MmCardGetReg(MMCIFC * ifc, uint8_t cmd, uint8_t * rbp, int siz)
00907 {
00908     int rc = -1;
00909     int retries = MMC_MAX_REG_POLLS;
00910     int i;
00911 
00912     /* Gain mutex access. */
00913     NutEventWait(&mutex, 0);
00914 
00915     while (retries--) {
00916         /* Send the command to the card. This will select the card. */
00917         MmCardTxCmd(ifc, cmd, 0);
00918         /* Wait for OK response from the card. */
00919         if (MmCardRxR1(ifc) == 0x00) {
00920             /* Wait for data from the card. */
00921             if (MmCardRxR1(ifc) == 0xFE) {
00922                 for (i = 0; i < siz; i++) {
00923                     *rbp++ = (*ifc->mmcifc_io) (0xFF);
00924                 }
00925                 /* Ignore the CRC. */
00926                 (*ifc->mmcifc_io) (0xFF);
00927                 (*ifc->mmcifc_io) (0xFF);
00928                 /* De-activate card selection. */
00929                 (*ifc->mmcifc_cs) (0);
00930                 /* Return a positive result. */
00931                 rc = 0;
00932                 break;
00933             }
00934         }
00935         /* De-activate card selection. */
00936         (*ifc->mmcifc_cs) (0);
00937     }
00938 
00939     /* Release mutex access. */
00940     NutEventPost(&mutex);
00941 
00942     return rc;
00943 }
00944 
00968 int MmCardIOCtl(NUTDEVICE * dev, int req, void *conf)
00969 {
00970     int rc = 0;
00971     MMCIFC *ifc = (MMCIFC *) dev->dev_icb;
00972 
00973     switch (req) {
00974     case NUTBLKDEV_MEDIAAVAIL:
00975         {
00976             int *flg = (int *) conf;
00977             *flg = (*ifc->mmcifc_cd) ();
00978         }
00979         break;
00980     case NUTBLKDEV_MEDIACHANGE:
00981         {
00982             int *flg = (int *) conf;
00983             if ((*ifc->mmcifc_cd) () != 1) {
00984                 *flg = 1;
00985             } else {
00986                 *flg = 0;
00987             }
00988         }
00989         break;
00990     case NUTBLKDEV_INFO:
00991         {
00992             BLKPAR_INFO *par = (BLKPAR_INFO *) conf;
00993             MMCFCB *fcb = (MMCFCB *) par->par_nfp->nf_fcb;
00994 
00995             par->par_nblks = fcb->fcb_part.part_sects;
00996             par->par_blksz = MMC_BLOCK_SIZE;
00997             par->par_blkbp = fcb->fcb_blkbuf;
00998         }
00999         break;
01000     case NUTBLKDEV_SEEK:
01001         {
01002             BLKPAR_SEEK *par = (BLKPAR_SEEK *) conf;
01003             MMCFCB *fcb = (MMCFCB *) par->par_nfp->nf_fcb;
01004 
01005             fcb->fcb_blknum = par->par_blknum;
01006         }
01007         break;
01008     case MMCARD_GETSTATUS:
01009         {
01010             uint16_t *s = (uint16_t *) conf;
01011 
01012             /* Gain mutex access. */
01013             NutEventWait(&mutex, 0);
01014 
01015             MmCardTxCmd(ifc, MMCMD_SEND_STATUS, 0);
01016             *s = MmCardRxR2(ifc);
01017 
01018             /* Release mutex access. */
01019             NutEventPost(&mutex);
01020         }
01021         break;
01022     case MMCARD_GETOCR:
01023         /* Gain mutex access. */
01024         NutEventWait(&mutex, 0);
01025 
01026         MmCardTxCmd(ifc, MMCMD_READ_OCR, 0);
01027         if (MmCardRxR3(ifc, (uint32_t *) conf) != MMR1_IDLE_STATE) {
01028             rc = -1;
01029         }
01030 
01031         /* Release mutex access. */
01032         NutEventPost(&mutex);
01033         break;
01034     case MMCARD_GETCID:
01035         rc = MmCardGetReg(ifc, MMCMD_SEND_CID, (uint8_t *) conf, sizeof(MMC_CID));
01036         break;
01037     case MMCARD_GETCSD:
01038         rc = MmCardGetReg(ifc, MMCMD_SEND_CSD, (uint8_t *) conf, sizeof(MMC_CSD));
01039         break;
01040     default:
01041         rc = -1;
01042         break;
01043     }
01044     return rc;
01045 }
01046 
01058 int MmCardDevInit(NUTDEVICE * dev)
01059 {
01060     return 0;
01061 }
01062