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 
00080 #include <cfg/mmci.h>
00081 
00082 #if 0
00083 /* Use for local debugging. */
00084 #define NUTDEBUG
00085 #include <stdio.h>
00086 #endif
00087 
00088 #include <errno.h>
00089 #include <string.h>
00090 #include <stdlib.h>
00091 
00092 #include <sys/heap.h>
00093 #include <sys/timer.h>
00094 #include <sys/event.h>
00095 #include <fs/dospart.h>
00096 #include <fs/fs.h>
00097 
00098 #include <dev/blockdev.h>
00099 #include <dev/mmcard.h>
00100 
00105 
00106 #ifndef MMC_BLOCK_SIZE
00107 
00113 #define MMC_BLOCK_SIZE          512
00114 #endif
00115 
00116 #ifndef MMC_MAX_INIT_POLLS
00117 
00124 #define MMC_MAX_INIT_POLLS      512
00125 #endif
00126 
00127 #ifndef MMC_MAX_RESET_POLLS
00128 
00133 #define MMC_MAX_RESET_POLLS     255
00134 #endif
00135 
00136 #ifndef MMC_MAX_WRITE_POLLS
00137 
00144 #define MMC_MAX_WRITE_POLLS     1024
00145 #endif
00146 
00147 #ifndef MMC_MAX_WRITE_RETRIES
00148 
00153 #define MMC_MAX_WRITE_RETRIES   32
00154 #endif
00155 
00156 #ifndef MMC_MAX_READ_RETRIES
00157 
00162 #define MMC_MAX_READ_RETRIES    8
00163 #endif
00164 
00165 #ifndef MMC_MAX_REG_POLLS
00166 
00171 #define MMC_MAX_REG_POLLS       512
00172 #endif
00173 
00174 #ifndef MMC_MAX_CMDACK_POLLS
00175 
00182 #define MMC_MAX_CMDACK_POLLS    1024
00183 #endif
00184 
00185 #ifndef MMC_MAX_R1_POLLS
00186 
00191 #define MMC_MAX_R1_POLLS        1024
00192 #endif
00193 
00197 typedef struct _MMCFCB {
00200     NUTDEVICE *fcb_fsdev;
00201 
00204     DOSPART fcb_part;
00205 
00213     u_long fcb_blknum;
00214 
00224     u_char fcb_blkbuf[MMC_BLOCK_SIZE];
00225 } MMCFCB;
00226 
00227 /*
00228  * Several routines call NutSleep, which results in a context switch.
00229  * This mutual exclusion semaphore takes care, that multiple threads
00230  * do not interfere with each other.
00231  */
00232 static HANDLE mutex;
00233 
00241 static void MmCardTxCmd(MMCIFC * ifc, u_char cmd, u_long param)
00242 {
00243     u_int tmo = MMC_MAX_CMDACK_POLLS;
00244     u_char ch;
00245 
00246     /* Enable card select. */
00247     (*ifc->mmcifc_cs) (1);
00248     /*
00249      * Repeat sending nothing until we receive nothing. Actually
00250      * it should be sufficient to send a single 0xFF value, but
00251      * running a loop seems to fix certain kind of sync problems.
00252      */
00253     while ((ch = (*ifc->mmcifc_io) (0xFF)) != 0xFF) {
00254         if (--tmo == 0) {
00255 #ifdef NUTDEBUG
00256             printf("[MMCmd%u Timeout %02X]\n", cmd, ch);
00257 #endif
00258             break;
00259         }
00260         if (tmo < MMC_MAX_CMDACK_POLLS / 4) {
00261             NutSleep(1);
00262         }
00263     }
00264     /* Send command and parameter. */
00265     (*ifc->mmcifc_io) (MMCMD_HOST | cmd);
00266     (*ifc->mmcifc_io) ((u_char) (param >> 24));
00267     (*ifc->mmcifc_io) ((u_char) (param >> 16));
00268     (*ifc->mmcifc_io) ((u_char) (param >> 8));
00269     (*ifc->mmcifc_io) ((u_char) param);
00270     /*
00271      * We are running with CRC disabled. However, the reset command must
00272      * be send with a valid CRC. Fortunately this command is sent with a
00273      * fixed parameter value of zero, which results in a fixed CRC value
00274      */
00275     (*ifc->mmcifc_io) (MMCMD_RESET_CRC);
00276 }
00277 
00288 static u_char MmCardRxR1(MMCIFC * ifc)
00289 {
00290     u_char rc;
00291     int i;
00292 
00293     for (i = 0; i < MMC_MAX_R1_POLLS; i++) {
00294         if ((rc = (*ifc->mmcifc_io) (0xFF)) != 0xFF) {
00295             break;
00296         }
00297     }
00298     return rc;
00299 }
00300 
00311 static u_short MmCardRxR2(MMCIFC * ifc)
00312 {
00313     u_short rc;
00314 
00315     rc = MmCardRxR1(ifc);
00316     rc <<= 8;
00317     rc += (*ifc->mmcifc_io) (0xFF);
00318 
00319     return rc;
00320 }
00321 
00333 static u_char MmCardRxR3(MMCIFC * ifc, u_long * ocr)
00334 {
00335     u_char rc;
00336     int i;
00337 
00338     /* The first byte is equal to the R1 response. */
00339     rc = MmCardRxR1(ifc);
00340     /* Receive the operating condition. */
00341     for (i = 0; i < 4; i++) {
00342         *ocr <<= 8;
00343         *ocr |= (*ifc->mmcifc_io) (0xFF);
00344     }
00345     return rc;
00346 }
00347 
00355 static int MmCardReset(MMCIFC * ifc)
00356 {
00357     int i;
00358     u_char rsp;
00359 
00360     /*
00361      * Initialize the low level card interface.
00362      */
00363     if ((*ifc->mmcifc_in) ()) {
00364         return -1;
00365     }
00366 
00367     /*
00368      * 80 bits of ones with deactivated chip select will put the card 
00369      * in SPI mode.
00370      */
00371     (*ifc->mmcifc_cs) (0);
00372     for (i = 0; i < 10; i++) {
00373         (*ifc->mmcifc_io) (0xFF);
00374     }
00375 
00376     /*
00377      * Switch to idle state and wait until initialization is running
00378      * or idle state is reached.
00379      */
00380     for (i = 0; i < MMC_MAX_RESET_POLLS; i++) {
00381         MmCardTxCmd(ifc, MMCMD_GO_IDLE_STATE, 0);
00382         rsp = MmCardRxR1(ifc);
00383         (*ifc->mmcifc_cs) (0);
00384         if (rsp == MMR1_IDLE_STATE || rsp == MMR1_NOT_IDLE) {
00385             return 0;
00386         }
00387     }
00388     return -1;
00389 }
00390 
00401 static int MmCardInit(MMCIFC * ifc)
00402 {
00403     int i;
00404     u_char rsp;
00405 
00406     /*
00407      * Try to switch to SPI mode. Looks like a retry helps to fix
00408      * certain synchronization problems.
00409      */
00410     if (MmCardReset(ifc)) {
00411         if (MmCardReset(ifc)) {
00412 #ifdef NUTDEBUG
00413             printf("[CardReset failed]");
00414 #endif
00415             return -1;
00416         }
00417     }
00418 
00419     /*
00420      * Wait for a really long time until card is initialized
00421      * and enters idle state.
00422      */
00423     for (i = 0; i < MMC_MAX_INIT_POLLS; i++) {
00424         /*
00425          * In SPI mode SEND_OP_COND is a dummy, used to poll the card
00426          * for initialization finished. Thus, there are no parameters
00427          * and no operation condition data is sent back.
00428          */
00429         MmCardTxCmd(ifc, MMCMD_SEND_OP_COND, 0);
00430         rsp = MmCardRxR1(ifc);
00431         (*ifc->mmcifc_cs) (0);
00432         if (rsp == MMR1_IDLE_STATE) {
00433 #ifdef NUTDEBUG
00434             printf("[CardIdle]");
00435 #endif
00436             /* Initialize MMC access mutex semaphore. */
00437             NutEventPost(&mutex);
00438             return 0;
00439         }
00440         if (i > MMC_MAX_INIT_POLLS / 4) {
00441             NutSleep(1);
00442         }
00443     }
00444 #ifdef NUTDEBUG
00445     printf("[CardInit failed]");
00446 #endif
00447     return -1;
00448 }
00449 
00460 static int MmCardReadOrVerify(MMCIFC * ifc, u_long blk, u_char * buf, int vflg)
00461 {
00462     int rc = -1;
00463     int retries = 64;
00464     int i;
00465     u_char rsp;
00466 
00467     /* Gain mutex access. */
00468     NutEventWait(&mutex, 0);
00469 
00470     while (retries--) {
00471         MmCardTxCmd(ifc, MMCMD_READ_SINGLE_BLOCK, blk << 9);
00472         if ((rsp = MmCardRxR1(ifc)) == 0x00) {
00473             if ((rsp = MmCardRxR1(ifc)) == 0xFE) {
00474                 rc = 0;
00475                 if (vflg) {
00476                     for (i = 0; i < MMC_BLOCK_SIZE; i++) {
00477                         if (*buf != (*ifc->mmcifc_io) (0xFF)) {
00478                             rc = -1;
00479                         }
00480                         buf++;
00481                     }
00482                 } else {
00483                     for (i = 0; i < MMC_BLOCK_SIZE; i++) {
00484                         *buf = (*ifc->mmcifc_io) (0xFF);
00485                         buf++;
00486                     }
00487                 }
00488                 (*ifc->mmcifc_io) (0xff);
00489                 (*ifc->mmcifc_io) (0xff);
00490                 (*ifc->mmcifc_cs) (0);
00491                 break;
00492             }
00493         }
00494         (*ifc->mmcifc_cs) (0);
00495     }
00496 
00497     /* Release mutex access. */
00498     NutEventPost(&mutex);
00499 
00500     return rc;
00501 }
00502 
00512 static int MmCardWrite(MMCIFC * ifc, u_long blk, CONST u_char * buf)
00513 {
00514     int rc = -1;
00515     int retries = MMC_MAX_WRITE_RETRIES;
00516     int tmo;
00517     int i;
00518     u_char rsp;
00519 
00520     /* Gain mutex access. */
00521     NutEventWait(&mutex, 0);
00522 
00523     while (retries--) {
00524         MmCardTxCmd(ifc, MMCMD_WRITE_BLOCK, blk << 9);
00525         if ((rsp = MmCardRxR1(ifc)) == 0x00) {
00526             (*ifc->mmcifc_io) (0xFF);
00527             (*ifc->mmcifc_io) (0xFE);
00528             for (i = 0; i < MMC_BLOCK_SIZE; i++) {
00529                 (*ifc->mmcifc_io) (*buf);
00530                 buf++;
00531             }
00532             // (*ifc->mmcifc_io)(0xFF);
00533             // (*ifc->mmcifc_io)(0xFF);
00534             if ((rsp = MmCardRxR1(ifc)) == 0xE5) {
00535                 for (tmo = 0; tmo < MMC_MAX_WRITE_POLLS; tmo++) {
00536                     if ((*ifc->mmcifc_io) (0xFF) == 0xFF) {
00537                         break;
00538                     }
00539                     if (tmo > MMC_MAX_WRITE_POLLS - MMC_MAX_WRITE_POLLS / 32) {
00540                         NutSleep(1);
00541                     }
00542                 }
00543                 if (tmo) {
00544                     rc = 0;
00545                     break;
00546                 }
00547 #ifdef NUTDEBUG
00548                 printf("[MMCWR Timeout]\n");
00549 #endif
00550             }
00551         }
00552         (*ifc->mmcifc_cs) (0);
00553     }
00554     (*ifc->mmcifc_cs) (0);
00555 
00556     /* Release mutex access. */
00557     NutEventPost(&mutex);
00558 
00559     return rc;
00560 }
00561 
00577 int MmCardBlockRead(NUTFILE * nfp, void *buffer, int num)
00578 {
00579     MMCFCB *fcb = (MMCFCB *) nfp->nf_fcb;
00580     u_long blk = fcb->fcb_blknum;
00581     NUTDEVICE *dev = (NUTDEVICE *) nfp->nf_dev;
00582     MMCIFC *ifc = (MMCIFC *) dev->dev_icb;
00583 
00584     if ((*ifc->mmcifc_cd) () != 1) {
00585         return -1;
00586     }
00587     if (buffer == 0) {
00588         buffer = fcb->fcb_blkbuf;
00589     }
00590     blk += fcb->fcb_part.part_sect_offs;
00591 
00592 #ifdef MMC_VERIFY_AFTER
00593     {
00594         int i;
00595         /*
00596          * It would be much better to verify the checksum than to re-read
00597          * and verify the data block.
00598          */
00599         for (i = 0; i < MMC_MAX_READ_RETRIES; i++) {
00600             if (MmCardReadOrVerify(ifc, blk, buffer, 0) == 0) {
00601                 if (MmCardReadOrVerify(ifc, blk, buffer, 1) == 0) {
00602                     return 1;
00603                 }
00604             }
00605         }
00606     }
00607 #else
00608     if (MmCardReadOrVerify(ifc, blk, buffer, 0) == 0) {
00609         return 1;
00610     }
00611 #endif
00612     return -1;
00613 }
00614 
00630 int MmCardBlockWrite(NUTFILE * nfp, CONST void *buffer, int num)
00631 {
00632     MMCFCB *fcb = (MMCFCB *) nfp->nf_fcb;
00633     u_long blk = fcb->fcb_blknum;
00634     NUTDEVICE *dev = (NUTDEVICE *) nfp->nf_dev;
00635     MMCIFC *ifc = (MMCIFC *) dev->dev_icb;
00636 
00637     if ((*ifc->mmcifc_cd) () != 1) {
00638         return -1;
00639     }
00640     if (buffer == 0) {
00641         buffer = fcb->fcb_blkbuf;
00642     }
00643     blk += fcb->fcb_part.part_sect_offs;
00644 
00645 #ifdef MMC_VERIFY_AFTER
00646     {
00647         int i;
00648 
00649         for (i = 0; i < MMC_MAX_READ_RETRIES; i++) {
00650             if (MmCardWrite(ifc, blk, buffer) == 0) {
00651                 if (MmCardReadOrVerify(ifc, blk, (void *) buffer, 1) == 0) {
00652                     return 1;
00653                 }
00654                 if (MmCardReadOrVerify(ifc, blk, (void *) buffer, 1) == 0) {
00655                     return 1;
00656                 }
00657             }
00658         }
00659     }
00660 #else
00661     if (MmCardWrite(ifc, blk, buffer) == 0) {
00662         return 1;
00663     }
00664 #endif
00665     return -1;
00666 }
00667 
00668 #ifdef __HARVARD_ARCH__
00669 
00688 int MmCardBlockWrite_P(NUTFILE * nfp, PGM_P buffer, int num)
00689 {
00690     return -1;
00691 }
00692 #endif
00693 
00719 NUTFILE *MmCardMount(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00720 {
00721     int partno = 0;
00722     int i;
00723     NUTDEVICE *fsdev;
00724     NUTFILE *nfp;
00725     MMCFCB *fcb;
00726     DOSPART *part;
00727     MMCIFC *ifc = (MMCIFC *) dev->dev_icb;
00728     FSCP_VOL_MOUNT mparm;
00729 
00730     /* Return an error if no card is detected. */
00731     if ((*ifc->mmcifc_cd) () == 0) {
00732         errno = ENODEV;
00733         return NUTFILE_EOF;
00734     }
00735 
00736     /* Set the card in SPI mode. */
00737     if (MmCardInit(ifc)) {
00738         errno = ENODEV;
00739         return NUTFILE_EOF;
00740     }
00741 
00742     /* Parse the name for a partition number and a file system driver. */
00743     if (*name) {
00744         partno = atoi(name);
00745         do {
00746             name++;
00747         } while (*name && *name != '/');
00748         if (*name == '/') {
00749             name++;
00750         }
00751     }
00752 
00753     /*
00754      * Check the list of registered devices for the given name of the
00755      * files system driver. If none has been specified, get the first
00756      * file system driver in the list. Hopefully the application
00757      * registered one only.
00758      */
00759     for (fsdev = nutDeviceList; fsdev; fsdev = fsdev->dev_next) {
00760         if (*name == 0) {
00761             if (fsdev->dev_type == IFTYP_FS) {
00762                 break;
00763             }
00764         } else if (strcmp(fsdev->dev_name, name) == 0) {
00765             break;
00766         }
00767     }
00768 
00769     if (fsdev == 0) {
00770 #ifdef NUTDEBUG
00771         printf("[No FSDriver]");
00772 #endif
00773         errno = ENODEV;
00774         return NUTFILE_EOF;
00775     }
00776 
00777     if ((fcb = NutHeapAllocClear(sizeof(MMCFCB))) == 0) {
00778         errno = ENOMEM;
00779         return NUTFILE_EOF;
00780     }
00781     fcb->fcb_fsdev = fsdev;
00782 
00783     /* Read MBR. */
00784     if (MmCardReadOrVerify(ifc, 0, fcb->fcb_blkbuf, 0)) {
00785         NutHeapFree(fcb);
00786         return NUTFILE_EOF;
00787     }
00788 
00789     /* Read partition table. */
00790     part = (DOSPART *) & fcb->fcb_blkbuf[DOSPART_SECTORPOS];
00791     for (i = 1; i <= 4; i++) {
00792         if (partno) {
00793             if (i == partno) {
00794                 /* Found specified partition number. */
00795                 fcb->fcb_part = *part;
00796                 break;
00797             }
00798         } else if (part->part_state & 0x80) {
00799             /* Located first active partition. */
00800             fcb->fcb_part = *part;
00801             break;
00802         }
00803         part++;
00804     }
00805 
00806     if (fcb->fcb_part.part_type == PTYPE_EMPTY) {
00807         NutHeapFree(fcb);
00808         return NUTFILE_EOF;
00809     }
00810 
00811     if ((nfp = NutHeapAlloc(sizeof(NUTFILE))) == 0) {
00812         NutHeapFree(fcb);
00813         errno = ENOMEM;
00814         return NUTFILE_EOF;
00815     }
00816     nfp->nf_next = 0;
00817     nfp->nf_dev = dev;
00818     nfp->nf_fcb = fcb;
00819 
00820     /*
00821      * Mount the file system volume.
00822      */
00823     mparm.fscp_bmnt = nfp;
00824     mparm.fscp_part_type = fcb->fcb_part.part_type;
00825     if (fsdev->dev_ioctl(fsdev, FS_VOL_MOUNT, &mparm)) {
00826         MmCardUnmount(nfp);
00827         return NUTFILE_EOF;
00828     }
00829     return nfp;
00830 }
00831 
00840 int MmCardUnmount(NUTFILE * nfp)
00841 {
00842     int rc = -1;
00843 
00844     if (nfp) {
00845         MMCFCB *fcb = (MMCFCB *) nfp->nf_fcb;
00846 
00847         if (fcb) {
00848             NUTDEVICE *dev = (NUTDEVICE *) nfp->nf_dev;
00849             MMCIFC *ifc = (MMCIFC *) dev->dev_icb;
00850 
00851             if ((*ifc->mmcifc_cd) () == 1) {
00852                 rc = fcb->fcb_fsdev->dev_ioctl(fcb->fcb_fsdev, FS_VOL_UNMOUNT, NULL);
00853             }
00854             NutHeapFree(fcb);
00855         }
00856         NutHeapFree(nfp);
00857     }
00858     return rc;
00859 }
00860 
00872 static int MmCardGetReg(MMCIFC * ifc, u_char cmd, u_char * rbp, int siz)
00873 {
00874     int rc = -1;
00875     int retries = MMC_MAX_REG_POLLS;
00876     int i;
00877 
00878     /* Gain mutex access. */
00879     NutEventWait(&mutex, 0);
00880 
00881     while (retries--) {
00882         /* Send the command to the card. This will select the card. */
00883         MmCardTxCmd(ifc, cmd, 0);
00884         /* Wait for OK response from the card. */
00885         if (MmCardRxR1(ifc) == 0x00) {
00886             /* Wait for data from the card. */
00887             if (MmCardRxR1(ifc) == 0xFE) {
00888                 for (i = 0; i < siz; i++) {
00889                     *rbp++ = (*ifc->mmcifc_io) (0xFF);
00890                 }
00891                 /* Ignore the CRC. */
00892                 (*ifc->mmcifc_io) (0xFF);
00893                 (*ifc->mmcifc_io) (0xFF);
00894                 /* De-activate card selection. */
00895                 (*ifc->mmcifc_cs) (0);
00896                 /* Return a positive result. */
00897                 rc = 0;
00898                 break;
00899             }
00900         }
00901         /* De-activate card selection. */
00902         (*ifc->mmcifc_cs) (0);
00903     }
00904 
00905     /* Release mutex access. */
00906     NutEventPost(&mutex);
00907 
00908     return rc;
00909 }
00910 
00934 int MmCardIOCtl(NUTDEVICE * dev, int req, void *conf)
00935 {
00936     int rc = 0;
00937     MMCIFC *ifc = (MMCIFC *) dev->dev_icb;
00938 
00939     switch (req) {
00940     case NUTBLKDEV_MEDIAAVAIL:
00941         {
00942             int *flg = (int *) conf;
00943             *flg = (*ifc->mmcifc_cd) ();
00944         }
00945         break;
00946     case NUTBLKDEV_MEDIACHANGE:
00947         {
00948             int *flg = (int *) conf;
00949             if ((*ifc->mmcifc_cd) () != 1) {
00950                 *flg = 1;
00951             } else {
00952                 *flg = 0;
00953             }
00954         }
00955         break;
00956     case NUTBLKDEV_INFO:
00957         {
00958             BLKPAR_INFO *par = (BLKPAR_INFO *) conf;
00959             MMCFCB *fcb = (MMCFCB *) par->par_nfp->nf_fcb;
00960 
00961             par->par_nblks = fcb->fcb_part.part_sects;
00962             par->par_blksz = MMC_BLOCK_SIZE;
00963             par->par_blkbp = fcb->fcb_blkbuf;
00964         }
00965         break;
00966     case NUTBLKDEV_SEEK:
00967         {
00968             BLKPAR_SEEK *par = (BLKPAR_SEEK *) conf;
00969             MMCFCB *fcb = (MMCFCB *) par->par_nfp->nf_fcb;
00970 
00971             fcb->fcb_blknum = par->par_blknum;
00972         }
00973         break;
00974     case MMCARD_GETSTATUS:
00975         {
00976             u_short *s = (u_short *) conf;
00977 
00978             /* Gain mutex access. */
00979             NutEventWait(&mutex, 0);
00980 
00981             MmCardTxCmd(ifc, MMCMD_SEND_STATUS, 0);
00982             *s = MmCardRxR2(ifc);
00983 
00984             /* Release mutex access. */
00985             NutEventPost(&mutex);
00986         }
00987         break;
00988     case MMCARD_GETOCR:
00989         /* Gain mutex access. */
00990         NutEventWait(&mutex, 0);
00991 
00992         MmCardTxCmd(ifc, MMCMD_READ_OCR, 0);
00993         if (MmCardRxR3(ifc, (u_long *) conf) != MMR1_IDLE_STATE) {
00994             rc = -1;
00995         }
00996 
00997         /* Release mutex access. */
00998         NutEventPost(&mutex);
00999         break;
01000     case MMCARD_GETCID:
01001         rc = MmCardGetReg(ifc, MMCMD_SEND_CID, (u_char *) conf, sizeof(MMC_CID));
01002         break;
01003     case MMCARD_GETCSD:
01004         rc = MmCardGetReg(ifc, MMCMD_SEND_CSD, (u_char *) conf, sizeof(MMC_CSD));
01005         break;
01006     default:
01007         rc = -1;
01008         break;
01009     }
01010     return rc;
01011 }
01012 
01024 int MmCardDevInit(NUTDEVICE * dev)
01025 {
01026     return 0;
01027 }
01028 

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