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 
00086 #include <cfg/mmci.h>
00087 
00088 #if 0
00089 /* Use for local debugging. */
00090 #define NUTDEBUG
00091 #include <stdio.h>
00092 #endif
00093 
00094 #include <errno.h>
00095 #include <string.h>
00096 #include <stdlib.h>
00097 
00098 #include <sys/heap.h>
00099 #include <sys/timer.h>
00100 #include <sys/event.h>
00101 #include <fs/dospart.h>
00102 #include <fs/fs.h>
00103 
00104 #include <dev/blockdev.h>
00105 #include <dev/mmcard.h>
00106 
00111 
00112 #ifndef MMC_BLOCK_SIZE
00113 
00119 #define MMC_BLOCK_SIZE          512
00120 #endif
00121 
00122 #ifndef MMC_MAX_INIT_POLLS
00123 
00130 #define MMC_MAX_INIT_POLLS      512
00131 #endif
00132 
00133 #ifndef MMC_MAX_RESET_POLLS
00134 
00139 #define MMC_MAX_RESET_POLLS     255
00140 #endif
00141 
00142 #ifndef MMC_MAX_WRITE_POLLS
00143 
00150 #define MMC_MAX_WRITE_POLLS     1024
00151 #endif
00152 
00153 #ifndef MMC_MAX_WRITE_RETRIES
00154 
00159 #define MMC_MAX_WRITE_RETRIES   32
00160 #endif
00161 
00162 #ifndef MMC_MAX_READ_RETRIES
00163 
00168 #define MMC_MAX_READ_RETRIES    8
00169 #endif
00170 
00171 #ifndef MMC_MAX_REG_POLLS
00172 
00177 #define MMC_MAX_REG_POLLS       512
00178 #endif
00179 
00180 #ifndef MMC_MAX_CMDACK_POLLS
00181 
00188 #define MMC_MAX_CMDACK_POLLS    1024
00189 #endif
00190 
00191 #ifndef MMC_MAX_R1_POLLS
00192 
00197 #define MMC_MAX_R1_POLLS        1024
00198 #endif
00199 
00203 typedef struct _MMCFCB {
00206     NUTDEVICE *fcb_fsdev;
00207 
00210     DOSPART fcb_part;
00211 
00219     uint32_t fcb_blknum;
00220 
00230     uint8_t fcb_blkbuf[MMC_BLOCK_SIZE];
00231 } MMCFCB;
00232 
00233 /*
00234  * Several routines call NutSleep, which results in a context switch.
00235  * This mutual exclusion semaphore takes care, that multiple threads
00236  * do not interfere with each other.
00237  */
00238 static HANDLE mutex;
00239 
00247 static void MmCardTxCmd(MMCIFC * ifc, uint8_t cmd, uint32_t param)
00248 {
00249     u_int tmo = MMC_MAX_CMDACK_POLLS;
00250     uint8_t ch;
00251 
00252     /* Enable card select. */
00253     (*ifc->mmcifc_cs) (1);
00254     /*
00255      * Repeat sending nothing until we receive nothing. Actually
00256      * it should be sufficient to send a single 0xFF value, but
00257      * running a loop seems to fix certain kind of sync problems.
00258      */
00259     while ((ch = (*ifc->mmcifc_io) (0xFF)) != 0xFF) {
00260         if (--tmo == 0) {
00261 #ifdef NUTDEBUG
00262             printf("[MMCmd%u Timeout %02X]\n", cmd, ch);
00263 #endif
00264             break;
00265         }
00266         if (tmo < MMC_MAX_CMDACK_POLLS / 4) {
00267             NutSleep(1);
00268         }
00269     }
00270     /* Send command and parameter. */
00271     (*ifc->mmcifc_io) (MMCMD_HOST | cmd);
00272     (*ifc->mmcifc_io) ((uint8_t) (param >> 24));
00273     (*ifc->mmcifc_io) ((uint8_t) (param >> 16));
00274     (*ifc->mmcifc_io) ((uint8_t) (param >> 8));
00275     (*ifc->mmcifc_io) ((uint8_t) param);
00276     /*
00277      * We are running with CRC disabled. However, the reset command must
00278      * be send with a valid CRC. Fortunately this command is sent with a
00279      * fixed parameter value of zero, which results in a fixed CRC value
00280      */
00281     (*ifc->mmcifc_io) (MMCMD_RESET_CRC);
00282 }
00283 
00294 static uint8_t MmCardRxR1(MMCIFC * ifc)
00295 {
00296     uint8_t rc;
00297     int i;
00298 
00299     for (i = 0; i < MMC_MAX_R1_POLLS; i++) {
00300         if ((rc = (*ifc->mmcifc_io) (0xFF)) != 0xFF) {
00301             break;
00302         }
00303     }
00304     return rc;
00305 }
00306 
00317 static uint16_t MmCardRxR2(MMCIFC * ifc)
00318 {
00319     uint16_t rc;
00320 
00321     rc = MmCardRxR1(ifc);
00322     rc <<= 8;
00323     rc += (*ifc->mmcifc_io) (0xFF);
00324 
00325     return rc;
00326 }
00327 
00339 static uint8_t MmCardRxR3(MMCIFC * ifc, uint32_t * ocr)
00340 {
00341     uint8_t rc;
00342     int i;
00343 
00344     /* The first byte is equal to the R1 response. */
00345     rc = MmCardRxR1(ifc);
00346     /* Receive the operating condition. */
00347     for (i = 0; i < 4; i++) {
00348         *ocr <<= 8;
00349         *ocr |= (*ifc->mmcifc_io) (0xFF);
00350     }
00351     return rc;
00352 }
00353 
00361 static int MmCardReset(MMCIFC * ifc)
00362 {
00363     int i;
00364     uint8_t rsp;
00365 
00366     /*
00367      * Initialize the low level card interface.
00368      */
00369     if ((*ifc->mmcifc_in) ()) {
00370         return -1;
00371     }
00372 
00373     /*
00374      * 80 bits of ones with deactivated chip select will put the card 
00375      * in SPI mode.
00376      */
00377     (*ifc->mmcifc_cs) (0);
00378     for (i = 0; i < 10; i++) {
00379         (*ifc->mmcifc_io) (0xFF);
00380     }
00381 
00382     /*
00383      * Switch to idle state and wait until initialization is running
00384      * or idle state is reached.
00385      */
00386     for (i = 0; i < MMC_MAX_RESET_POLLS; i++) {
00387         MmCardTxCmd(ifc, MMCMD_GO_IDLE_STATE, 0);
00388         rsp = MmCardRxR1(ifc);
00389         (*ifc->mmcifc_cs) (0);
00390         if (rsp == MMR1_IDLE_STATE || rsp == MMR1_NOT_IDLE) {
00391             return 0;
00392         }
00393     }
00394     return -1;
00395 }
00396 
00407 static int MmCardInit(MMCIFC * ifc)
00408 {
00409     int i;
00410     uint8_t rsp;
00411 
00412     /*
00413      * Try to switch to SPI mode. Looks like a retry helps to fix
00414      * certain synchronization problems.
00415      */
00416     if (MmCardReset(ifc)) {
00417         if (MmCardReset(ifc)) {
00418 #ifdef NUTDEBUG
00419             printf("[CardReset failed]");
00420 #endif
00421             return -1;
00422         }
00423     }
00424 
00425     /*
00426      * Wait for a really long time until card is initialized
00427      * and enters idle state.
00428      */
00429     for (i = 0; i < MMC_MAX_INIT_POLLS; i++) {
00430         /*
00431          * In SPI mode SEND_OP_COND is a dummy, used to poll the card
00432          * for initialization finished. Thus, there are no parameters
00433          * and no operation condition data is sent back.
00434          */
00435         MmCardTxCmd(ifc, MMCMD_SEND_OP_COND, 0);
00436         rsp = MmCardRxR1(ifc);
00437         (*ifc->mmcifc_cs) (0);
00438         if (rsp == MMR1_IDLE_STATE) {
00439 #ifdef NUTDEBUG
00440             printf("[CardIdle]");
00441 #endif
00442             /* Initialize MMC access mutex semaphore. */
00443             NutEventPost(&mutex);
00444             return 0;
00445         }
00446         if (i > MMC_MAX_INIT_POLLS / 4) {
00447             NutSleep(1);
00448         }
00449     }
00450 #ifdef NUTDEBUG
00451     printf("[CardInit failed]");
00452 #endif
00453     return -1;
00454 }
00455 
00466 static int MmCardReadOrVerify(MMCIFC * ifc, uint32_t blk, uint8_t * buf, int vflg)
00467 {
00468     int rc = -1;
00469     int retries = 64;
00470     int i;
00471     uint8_t rsp;
00472 
00473     /* Gain mutex access. */
00474     NutEventWait(&mutex, 0);
00475 
00476     while (retries--) {
00477         MmCardTxCmd(ifc, MMCMD_READ_SINGLE_BLOCK, blk << 9);
00478         if ((rsp = MmCardRxR1(ifc)) == 0x00) {
00479             if ((rsp = MmCardRxR1(ifc)) == 0xFE) {
00480                 rc = 0;
00481                 if (vflg) {
00482                     for (i = 0; i < MMC_BLOCK_SIZE; i++) {
00483                         if (*buf != (*ifc->mmcifc_io) (0xFF)) {
00484                             rc = -1;
00485                         }
00486                         buf++;
00487                     }
00488                 } else {
00489                     for (i = 0; i < MMC_BLOCK_SIZE; i++) {
00490                         *buf = (*ifc->mmcifc_io) (0xFF);
00491                         buf++;
00492                     }
00493                 }
00494                 (*ifc->mmcifc_io) (0xff);
00495                 (*ifc->mmcifc_io) (0xff);
00496                 (*ifc->mmcifc_cs) (0);
00497                 break;
00498             }
00499         }
00500         (*ifc->mmcifc_cs) (0);
00501     }
00502 
00503     /* Release mutex access. */
00504     NutEventPost(&mutex);
00505 
00506     return rc;
00507 }
00508 
00518 static int MmCardWrite(MMCIFC * ifc, uint32_t blk, CONST uint8_t * buf)
00519 {
00520     int rc = -1;
00521     int retries = MMC_MAX_WRITE_RETRIES;
00522     int tmo;
00523     int i;
00524     uint8_t rsp;
00525 
00526     /* Gain mutex access. */
00527     NutEventWait(&mutex, 0);
00528 
00529     while (retries--) {
00530         MmCardTxCmd(ifc, MMCMD_WRITE_BLOCK, blk << 9);
00531         if ((rsp = MmCardRxR1(ifc)) == 0x00) {
00532             (*ifc->mmcifc_io) (0xFF);
00533             (*ifc->mmcifc_io) (0xFE);
00534             for (i = 0; i < MMC_BLOCK_SIZE; i++) {
00535                 (*ifc->mmcifc_io) (*buf);
00536                 buf++;
00537             }
00538             // (*ifc->mmcifc_io)(0xFF);
00539             // (*ifc->mmcifc_io)(0xFF);
00540             if ((rsp = MmCardRxR1(ifc)) == 0xE5) {
00541                 for (tmo = 0; tmo < MMC_MAX_WRITE_POLLS; tmo++) {
00542                     if ((*ifc->mmcifc_io) (0xFF) == 0xFF) {
00543                         break;
00544                     }
00545                     if (tmo > MMC_MAX_WRITE_POLLS - MMC_MAX_WRITE_POLLS / 32) {
00546                         NutSleep(1);
00547                     }
00548                 }
00549                 if (tmo) {
00550                     rc = 0;
00551                     break;
00552                 }
00553 #ifdef NUTDEBUG
00554                 printf("[MMCWR Timeout]\n");
00555 #endif
00556             }
00557         }
00558         (*ifc->mmcifc_cs) (0);
00559     }
00560     (*ifc->mmcifc_cs) (0);
00561 
00562     /* Release mutex access. */
00563     NutEventPost(&mutex);
00564 
00565     return rc;
00566 }
00567 
00583 int MmCardBlockRead(NUTFILE * nfp, void *buffer, int num)
00584 {
00585     MMCFCB *fcb = (MMCFCB *) nfp->nf_fcb;
00586     uint32_t blk = fcb->fcb_blknum;
00587     NUTDEVICE *dev = (NUTDEVICE *) nfp->nf_dev;
00588     MMCIFC *ifc = (MMCIFC *) dev->dev_icb;
00589 
00590     if ((*ifc->mmcifc_cd) () != 1) {
00591         return -1;
00592     }
00593     if (buffer == 0) {
00594         buffer = fcb->fcb_blkbuf;
00595     }
00596     blk += fcb->fcb_part.part_sect_offs;
00597 
00598 #ifdef MMC_VERIFY_AFTER
00599     {
00600         int i;
00601         /*
00602          * It would be much better to verify the checksum than to re-read
00603          * and verify the data block.
00604          */
00605         for (i = 0; i < MMC_MAX_READ_RETRIES; i++) {
00606             if (MmCardReadOrVerify(ifc, blk, buffer, 0) == 0) {
00607                 if (MmCardReadOrVerify(ifc, blk, buffer, 1) == 0) {
00608                     return 1;
00609                 }
00610             }
00611         }
00612     }
00613 #else
00614     if (MmCardReadOrVerify(ifc, blk, buffer, 0) == 0) {
00615         return 1;
00616     }
00617 #endif
00618     return -1;
00619 }
00620 
00636 int MmCardBlockWrite(NUTFILE * nfp, CONST void *buffer, int num)
00637 {
00638     MMCFCB *fcb = (MMCFCB *) nfp->nf_fcb;
00639     uint32_t blk = fcb->fcb_blknum;
00640     NUTDEVICE *dev = (NUTDEVICE *) nfp->nf_dev;
00641     MMCIFC *ifc = (MMCIFC *) dev->dev_icb;
00642 
00643     if ((*ifc->mmcifc_cd) () != 1) {
00644         return -1;
00645     }
00646     if (buffer == 0) {
00647         buffer = fcb->fcb_blkbuf;
00648     }
00649     blk += fcb->fcb_part.part_sect_offs;
00650 
00651 #ifdef MMC_VERIFY_AFTER
00652     {
00653         int i;
00654 
00655         for (i = 0; i < MMC_MAX_READ_RETRIES; i++) {
00656             if (MmCardWrite(ifc, blk, buffer) == 0) {
00657                 if (MmCardReadOrVerify(ifc, blk, (void *) buffer, 1) == 0) {
00658                     return 1;
00659                 }
00660                 if (MmCardReadOrVerify(ifc, blk, (void *) buffer, 1) == 0) {
00661                     return 1;
00662                 }
00663             }
00664         }
00665     }
00666 #else
00667     if (MmCardWrite(ifc, blk, buffer) == 0) {
00668         return 1;
00669     }
00670 #endif
00671     return -1;
00672 }
00673 
00674 #ifdef __HARVARD_ARCH__
00675 
00694 int MmCardBlockWrite_P(NUTFILE * nfp, PGM_P buffer, int num)
00695 {
00696     return -1;
00697 }
00698 #endif
00699 
00725 NUTFILE *MmCardMount(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00726 {
00727     int partno = 0;
00728     int i;
00729     NUTDEVICE *fsdev;
00730     NUTFILE *nfp;
00731     MMCFCB *fcb;
00732     DOSPART *part;
00733     MMCIFC *ifc = (MMCIFC *) dev->dev_icb;
00734     FSCP_VOL_MOUNT mparm;
00735 
00736     /* Return an error if no card is detected. */
00737     if ((*ifc->mmcifc_cd) () == 0) {
00738         errno = ENODEV;
00739         return NUTFILE_EOF;
00740     }
00741 
00742     /* Set the card in SPI mode. */
00743     if (MmCardInit(ifc)) {
00744         errno = ENODEV;
00745         return NUTFILE_EOF;
00746     }
00747 
00748     /* Parse the name for a partition number and a file system driver. */
00749     if (*name) {
00750         partno = atoi(name);
00751         do {
00752             name++;
00753         } while (*name && *name != '/');
00754         if (*name == '/') {
00755             name++;
00756         }
00757     }
00758 
00759     /*
00760      * Check the list of registered devices for the given name of the
00761      * files system driver. If none has been specified, get the first
00762      * file system driver in the list. Hopefully the application
00763      * registered one only.
00764      */
00765     for (fsdev = nutDeviceList; fsdev; fsdev = fsdev->dev_next) {
00766         if (*name == 0) {
00767             if (fsdev->dev_type == IFTYP_FS) {
00768                 break;
00769             }
00770         } else if (strcmp(fsdev->dev_name, name) == 0) {
00771             break;
00772         }
00773     }
00774 
00775     if (fsdev == 0) {
00776 #ifdef NUTDEBUG
00777         printf("[No FSDriver]");
00778 #endif
00779         errno = ENODEV;
00780         return NUTFILE_EOF;
00781     }
00782 
00783     if ((fcb = NutHeapAllocClear(sizeof(MMCFCB))) == 0) {
00784         errno = ENOMEM;
00785         return NUTFILE_EOF;
00786     }
00787     fcb->fcb_fsdev = fsdev;
00788 
00789     /* Read MBR. */
00790     if (MmCardReadOrVerify(ifc, 0, fcb->fcb_blkbuf, 0)) {
00791         NutHeapFree(fcb);
00792         return NUTFILE_EOF;
00793     }
00794     /* Check for the cookie at the end of this sector. */
00795     if (fcb->fcb_blkbuf[DOSPART_MAGICPOS] != 0x55 || fcb->fcb_blkbuf[DOSPART_MAGICPOS + 1] != 0xAA) {
00796         NutHeapFree(fcb);
00797         return NUTFILE_EOF;
00798     }
00799     /* Check for the partition table. */
00800     if(fcb->fcb_blkbuf[DOSPART_TYPEPOS] == 'F' && 
00801        fcb->fcb_blkbuf[DOSPART_TYPEPOS + 1] == 'A' &&
00802        fcb->fcb_blkbuf[DOSPART_TYPEPOS + 2] == 'T') {
00803         /* No partition table. Assume FAT12 and 32MB size. */
00804         fcb->fcb_part.part_type = PTYPE_FAT12;
00805         fcb->fcb_part.part_sect_offs = 0;
00806         fcb->fcb_part.part_sects = 65536; /* How to find out? */
00807     }
00808     else {
00809         /* Read partition table. */
00810         part = (DOSPART *) & fcb->fcb_blkbuf[DOSPART_SECTORPOS];
00811         for (i = 1; i <= 4; i++) {
00812             if (partno) {
00813                 if (i == partno) {
00814                     /* Found specified partition number. */
00815                     fcb->fcb_part = *part;
00816                     break;
00817                 }
00818             } else if (part->part_state & 0x80) {
00819                 /* Located first active partition. */
00820                 fcb->fcb_part = *part;
00821                 break;
00822             }
00823             part++;
00824         }
00825 
00826         if (fcb->fcb_part.part_type == PTYPE_EMPTY) {
00827             NutHeapFree(fcb);
00828             return NUTFILE_EOF;
00829         }
00830     }
00831 
00832     if ((nfp = NutHeapAlloc(sizeof(NUTFILE))) == 0) {
00833         NutHeapFree(fcb);
00834         errno = ENOMEM;
00835         return NUTFILE_EOF;
00836     }
00837     nfp->nf_next = 0;
00838     nfp->nf_dev = dev;
00839     nfp->nf_fcb = fcb;
00840 
00841     /*
00842      * Mount the file system volume.
00843      */
00844     mparm.fscp_bmnt = nfp;
00845     mparm.fscp_part_type = fcb->fcb_part.part_type;
00846     if (fsdev->dev_ioctl(fsdev, FS_VOL_MOUNT, &mparm)) {
00847         MmCardUnmount(nfp);
00848         return NUTFILE_EOF;
00849     }
00850     return nfp;
00851 }
00852 
00861 int MmCardUnmount(NUTFILE * nfp)
00862 {
00863     int rc = -1;
00864 
00865     if (nfp) {
00866         MMCFCB *fcb = (MMCFCB *) nfp->nf_fcb;
00867 
00868         if (fcb) {
00869             NUTDEVICE *dev = (NUTDEVICE *) nfp->nf_dev;
00870             MMCIFC *ifc = (MMCIFC *) dev->dev_icb;
00871 
00872             if ((*ifc->mmcifc_cd) () == 1) {
00873                 rc = fcb->fcb_fsdev->dev_ioctl(fcb->fcb_fsdev, FS_VOL_UNMOUNT, NULL);
00874             }
00875             NutHeapFree(fcb);
00876         }
00877         NutHeapFree(nfp);
00878     }
00879     return rc;
00880 }
00881 
00893 static int MmCardGetReg(MMCIFC * ifc, uint8_t cmd, uint8_t * rbp, int siz)
00894 {
00895     int rc = -1;
00896     int retries = MMC_MAX_REG_POLLS;
00897     int i;
00898 
00899     /* Gain mutex access. */
00900     NutEventWait(&mutex, 0);
00901 
00902     while (retries--) {
00903         /* Send the command to the card. This will select the card. */
00904         MmCardTxCmd(ifc, cmd, 0);
00905         /* Wait for OK response from the card. */
00906         if (MmCardRxR1(ifc) == 0x00) {
00907             /* Wait for data from the card. */
00908             if (MmCardRxR1(ifc) == 0xFE) {
00909                 for (i = 0; i < siz; i++) {
00910                     *rbp++ = (*ifc->mmcifc_io) (0xFF);
00911                 }
00912                 /* Ignore the CRC. */
00913                 (*ifc->mmcifc_io) (0xFF);
00914                 (*ifc->mmcifc_io) (0xFF);
00915                 /* De-activate card selection. */
00916                 (*ifc->mmcifc_cs) (0);
00917                 /* Return a positive result. */
00918                 rc = 0;
00919                 break;
00920             }
00921         }
00922         /* De-activate card selection. */
00923         (*ifc->mmcifc_cs) (0);
00924     }
00925 
00926     /* Release mutex access. */
00927     NutEventPost(&mutex);
00928 
00929     return rc;
00930 }
00931 
00955 int MmCardIOCtl(NUTDEVICE * dev, int req, void *conf)
00956 {
00957     int rc = 0;
00958     MMCIFC *ifc = (MMCIFC *) dev->dev_icb;
00959 
00960     switch (req) {
00961     case NUTBLKDEV_MEDIAAVAIL:
00962         {
00963             int *flg = (int *) conf;
00964             *flg = (*ifc->mmcifc_cd) ();
00965         }
00966         break;
00967     case NUTBLKDEV_MEDIACHANGE:
00968         {
00969             int *flg = (int *) conf;
00970             if ((*ifc->mmcifc_cd) () != 1) {
00971                 *flg = 1;
00972             } else {
00973                 *flg = 0;
00974             }
00975         }
00976         break;
00977     case NUTBLKDEV_INFO:
00978         {
00979             BLKPAR_INFO *par = (BLKPAR_INFO *) conf;
00980             MMCFCB *fcb = (MMCFCB *) par->par_nfp->nf_fcb;
00981 
00982             par->par_nblks = fcb->fcb_part.part_sects;
00983             par->par_blksz = MMC_BLOCK_SIZE;
00984             par->par_blkbp = fcb->fcb_blkbuf;
00985         }
00986         break;
00987     case NUTBLKDEV_SEEK:
00988         {
00989             BLKPAR_SEEK *par = (BLKPAR_SEEK *) conf;
00990             MMCFCB *fcb = (MMCFCB *) par->par_nfp->nf_fcb;
00991 
00992             fcb->fcb_blknum = par->par_blknum;
00993         }
00994         break;
00995     case MMCARD_GETSTATUS:
00996         {
00997             uint16_t *s = (uint16_t *) conf;
00998 
00999             /* Gain mutex access. */
01000             NutEventWait(&mutex, 0);
01001 
01002             MmCardTxCmd(ifc, MMCMD_SEND_STATUS, 0);
01003             *s = MmCardRxR2(ifc);
01004 
01005             /* Release mutex access. */
01006             NutEventPost(&mutex);
01007         }
01008         break;
01009     case MMCARD_GETOCR:
01010         /* Gain mutex access. */
01011         NutEventWait(&mutex, 0);
01012 
01013         MmCardTxCmd(ifc, MMCMD_READ_OCR, 0);
01014         if (MmCardRxR3(ifc, (uint32_t *) conf) != MMR1_IDLE_STATE) {
01015             rc = -1;
01016         }
01017 
01018         /* Release mutex access. */
01019         NutEventPost(&mutex);
01020         break;
01021     case MMCARD_GETCID:
01022         rc = MmCardGetReg(ifc, MMCMD_SEND_CID, (uint8_t *) conf, sizeof(MMC_CID));
01023         break;
01024     case MMCARD_GETCSD:
01025         rc = MmCardGetReg(ifc, MMCMD_SEND_CSD, (uint8_t *) conf, sizeof(MMC_CSD));
01026         break;
01027     default:
01028         rc = -1;
01029         break;
01030     }
01031     return rc;
01032 }
01033 
01045 int MmCardDevInit(NUTDEVICE * dev)
01046 {
01047     return 0;
01048 }
01049 

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/