Nut/OS  4.10.3
API Reference
at91_mci.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 by egnite Software GmbH.
00003  * Copyright (C) 2008, 2011-2012 by egnite GmbH.
00004  *
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted provided that the following conditions
00009  * are met:
00010  *
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  * 3. Neither the name of the copyright holders nor the names of
00017  *    contributors may be used to endorse or promote products derived
00018  *    from this software without specific prior written permission.
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00021  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00024  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00025  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00026  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00027  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00028  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00029  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00030  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00031  * SUCH DAMAGE.
00032  *
00033  * For additional information see http://www.ethernut.de/
00034  */
00035 
00059 #include <cfg/arch.h>
00060 #include <cfg/arch/gpio.h>
00061 #include <cfg/mmci.h>
00062 
00063 #include <errno.h>
00064 #include <string.h>
00065 #include <stdlib.h>
00066 
00067 #include <sys/heap.h>
00068 #include <sys/timer.h>
00069 #include <sys/event.h>
00070 #include <fs/dospart.h>
00071 #include <fs/fs.h>
00072 
00073 #include <dev/blockdev.h>
00074 #include <dev/mmcard.h>
00075 #include <dev/at91_mci.h>
00076 
00077 
00078 #if 0
00079 /* Use for local debugging. */
00080 #define NUTDEBUG
00081 #include <stdio.h>
00082 #endif
00083 
00088 
00089 #ifndef MMC_BLOCK_SIZE
00090 #define MMC_BLOCK_SIZE  512
00091 #endif
00092 
00093 #ifndef MCI_INI_BITRATE
00094 /* MMC starts in open drain mode with 400 kHz max. clock. */
00095 #define MCI_INI_BITRATE 400000
00096 #endif
00097 
00098 #ifndef MCI_MMC_BITRATE
00099 /* Max. clock for MMC in push-pull mode is 20 MHz. */
00100 #define MCI_MMC_BITRATE 20000000
00101 #endif
00102 
00103 #ifndef MCI_SDC_BITRATE
00104 /* Max. clock for SD-Card is 25 MHz. */
00105 #define MCI_SDC_BITRATE 25000000
00106 #endif
00107 
00108 #ifndef MMCARD_VRANGE
00109 #define MMCARD_VRANGE   (MMCARD_32_33V | MMCARD_31_32V | MMCARD_30_31V)
00110 #endif
00111 
00112 #ifdef MCI_SLOTA
00113 
00114 #ifndef MMC_PINS_A
00115 #define MMC_PINS_A  _BV(PA6_MCDA0_A) | _BV(PA7_MCCDA_A) | _BV(PA8_MCCK_A) | _BV(PA9_MCDA1_A) | _BV(PA10_MCDA2_A) | _BV(PA11_MCDA3_A)
00116 #endif
00117 
00118 #ifndef MMC_PINS_B
00119 #define MMC_PINS_B  0
00120 #endif
00121 
00122 #else
00123 
00124 #ifndef MMC_PINS_A
00125 #define MMC_PINS_A  _BV(PA8_MCCK_A)
00126 #endif
00127 
00128 #ifndef MMC_PINS_B
00129 #define MMC_PINS_B  _BV(PA1_MCCDB_B) | _BV(PA0_MCDB0_B) | _BV(PA5_MCDB1_B) | _BV(PA4_MCDB2_B) | _BV(PA3_MCDB3_B)
00130 #endif
00131 
00132 #endif
00133 
00134 #define MCICMD_ALL_SEND_CID         (MMCMD_ALL_SEND_CID | MCI_MAXLAT | MCI_RSPTYP_136)
00135 #define MCICMD_DESELECT_CARD        (MMCMD_SELECT_CARD)
00136 #define MCICMD_GO_IDLE_STATE        (MMCMD_GO_IDLE_STATE)
00137 #define MCICMD_READ_SINGLE_BLOCK    (MMCMD_READ_SINGLE_BLOCK | MCI_TRCMD_START | MCI_TRDIR | MCI_MAXLAT | MCI_RSPTYP_48)
00138 #define MCICMD_SELECT_CARD          (MMCMD_SELECT_CARD | MCI_MAXLAT | MCI_RSPTYP_48)
00139 #define MCICMD_SEND_APP_CMD         (MMCMD_SEND_APP_CMD | MCI_MAXLAT | MCI_RSPTYP_48)
00140 #define MCICMD_SEND_APP_OP_COND     (MMCMD_SEND_APP_OP_COND | MCI_MAXLAT | MCI_RSPTYP_48)
00141 #define MCICMD_SEND_OP_COND         (MMCMD_SEND_OP_COND | MCI_MAXLAT | MCI_RSPTYP_48)
00142 #define MCICMD_SEND_RELATIVE_ADDR   (MMCMD_SEND_RELATIVE_ADDR | MCI_MAXLAT | MCI_RSPTYP_48)
00143 #define MCICMD_SEND_STATUS          (MMCMD_SEND_STATUS | MCI_MAXLAT | MCI_RSPTYP_48)
00144 #define MCICMD_SET_BLOCKLEN         (MMCMD_SET_BLOCKLEN | MCI_MAXLAT | MCI_RSPTYP_48)
00145 #define MCICMD_WRITE_BLOCK          (MMCMD_WRITE_BLOCK | MCI_TRCMD_START | MCI_MAXLAT | MCI_RSPTYP_48)
00146 
00147 #define MCICMD_IERROR   (MCI_RTOE | MCI_RENDE | MCI_RDIRE | MCI_RINDE)
00148 #define MCICMD_ERROR    (MCI_UNRE | MCI_OVRE | MCI_DTOE | MCI_DCRCE | MCI_RCRCE | MCICMD_IERROR)
00149 
00150 #define MCIFLG_SDCARD   0x00000001
00151 #define MCIFLG_4BIT     0x00000010
00152 
00156 typedef struct _MCIFC {
00158     uint32_t ifc_config;
00160     uint32_t ifc_opcond;
00162     uint32_t ifc_reladdr;
00164     uint8_t *ifc_buff;
00166     uint32_t ifc_resp[4];
00168     uint32_t ifc_cid[4];
00169 } MCIFC;
00170 
00174 typedef struct _MCIFCB {
00177     NUTDEVICE *fcb_fsdev;
00178 
00181     DOSPART fcb_part;
00182 
00190     uint32_t fcb_blknum;
00191 
00201     uint8_t fcb_blkbuf[MMC_BLOCK_SIZE];
00202 } MCIFCB;
00203 
00204 /*
00205  * Several routines call NutSleep, which results in a context switch.
00206  * This mutual exclusion semaphore takes care, that multiple threads
00207  * do not interfere with each other.
00208  */
00209 static HANDLE mutex;
00210 
00216 static uint32_t At91MciClockDiv(uint32_t clk)
00217 {
00218     uint32_t rc;
00219 
00220     /* MCI is driven by MCK/2. */
00221     rc = NutArchClockGet(NUT_HWCLK_PERIPHERAL) / 2;
00222     /* Compensate rounding error, but do not care about 10kHz. */
00223     rc += clk - 10000;
00224     /* Calculate the divider. */
00225     rc /= clk;
00226     /* Actual divider is 1 less, avoid underflow. */
00227     if (rc) {
00228         rc -= 1;
00229     }
00230     /* In reality, overflow will only happen when the caller requests
00231        a unrealistic low MCI clock. */
00232     if (rc > 255) {
00233         rc = 255;
00234     }
00235     return rc;
00236 }
00237 
00244 static void At91MciReset(int init)
00245 {
00246     uint32_t mode;
00247     uint32_t dtmo;
00248     uint32_t slot;
00249 
00250     /* Enable MCI clock. */
00251     outr(PMC_PCER, _BV(MCI_ID));
00252 
00253     if (init) {
00254         outr(MCI_IDR, 0xFFFFFFFF);
00255         /* Set initial configuration. */
00256         dtmo = MCI_DTOMUL_1M | MCI_DTOCYC;
00257         mode = MCI_RDPROOF | MCI_WRPROOF | (2 << MCI_PWSDIV_LSB);
00258         /* Slow start. */
00259         mode |= At91MciClockDiv(MCI_INI_BITRATE) << MCI_CLKDIV_LSB;
00260 #ifdef MCI_SLOTA
00261         slot = MCI_SDCSEL_SLOTA;
00262 #else
00263         slot = MCI_SDCSEL_SLOTB;
00264 #endif
00265     } else {
00266         /* Retrieve current configuration. */
00267         dtmo = inr(MCI_DTOR);
00268         mode = inr(MCI_MR) & 0xffff;
00269         slot = inr(MCI_SDCR);
00270     }
00271 
00272     /* Disable and software reset. */
00273     outr(MCI_CR, MCI_MCIDIS | MCI_SWRST);
00274 
00275     /* Set configuration values. */
00276     outr(MCI_DTOR, dtmo);
00277     outr(MCI_MR, mode);
00278     outr(MCI_SDCR, slot);
00279 
00280     /* Enable card interface. */
00281     outr(MCI_CR, MCI_MCIEN | MCI_PWSEN);
00282 }
00283 
00284 static void At91MciEnablePins(void)
00285 {
00286     /* Disable PIO lines used for MCI. */
00287     outr(PIOA_PDR, MMC_PINS_A | MMC_PINS_B);
00288     /* Enable peripherals. */
00289     outr(PIOA_ASR, MMC_PINS_A);
00290     outr(PIOA_BSR, MMC_PINS_B);
00291 }
00292 
00293 static void At91MciDisablePins(void)
00294 {
00295 #ifdef MCI0_PIN_SHARING
00296     /* Enable PIO input lines used for MCI. */
00297     outr(PIOA_ODR, MMC_PINS_A | MMC_PINS_B);
00298     outr(PIOA_PER, MMC_PINS_A | MMC_PINS_B);
00299 #endif
00300 }
00301 
00310 static int At91MciInit(NUTDEVICE * dev)
00311 {
00312     /* Initialize the MCI hardware. */
00313     At91MciReset(1);
00314 
00315     return 0;
00316 }
00317 
00327 static uint32_t At91MciTxCmd(MCIFC * ifc, uint32_t cmd, uint32_t param)
00328 {
00329     uint32_t sr;
00330     uint32_t rl;
00331     uint32_t i;
00332     uint32_t wfs = MCI_CMDRDY;
00333     uint32_t ces = MCICMD_IERROR;
00334 
00335     /*
00336      * Disable PDC.
00337      */
00338 #ifdef NUTDEBUG
00339     printf("[Cmd%lu,%lx]", cmd & MCI_CMDNB, param);
00340 #endif
00341     outr(MCI_PTCR, PDC_TXTDIS | PDC_RXTDIS);
00342     outr(MCI_MR, inr(MCI_MR) & ~(MCI_BLKLEN | MCI_PDCMODE));
00343     outr(MCI_RCR, 0);
00344     outr(MCI_RNCR, 0);
00345     outr(MCI_TCR, 0);
00346     outr(MCI_TNCR, 0);
00347 
00348     if (cmd & MCI_TRCMD_START) {
00349         /* Data transfer. Make sure that the buffer is set. */
00350         if (ifc->ifc_buff == NULL) {
00351             errno = EINVAL;
00352             return MCI_OVRE | MCI_UNRE;
00353         }
00354         /* Set block length and PDC mode. */
00355         outr(MCI_MR, (inr(MCI_MR) & ~MCI_BLKLEN) | (MMC_BLOCK_SIZE << MCI_BLKLEN_LSB) | MCI_PDCMODE);
00356         if (cmd & MCI_TRDIR) {
00357             /* Set PDC address and counter for reading. */
00358             outr(MCI_RPR, (uint32_t) ifc->ifc_buff);
00359             outr(MCI_RCR, MMC_BLOCK_SIZE / 4);
00360             /* Enable PDC read. */
00361             outr(MCI_PTCR, PDC_RXTEN);
00362             /* We will wait until end of data transmission. */
00363             wfs = MCI_ENDRX;
00364         } else {
00365             /* Set PDC address and counter for writing. */
00366             outr(MCI_TPR, (uint32_t) ifc->ifc_buff);
00367             outr(MCI_TCR, MMC_BLOCK_SIZE / 4);
00368             /* We will wait until data block ended. */
00369             wfs = MCI_BLKE;
00370         }
00371     }
00372     /* Set card parameter and command. */
00373     outr(MCI_ARGR, param);
00374     outr(MCI_CMDR, cmd);
00375 
00376     /* When writing, enable PDC after sending the command. */
00377     if ((cmd & (MCI_TRCMD_START | MCI_TRDIR)) == MCI_TRCMD_START) {
00378         outr(MCI_PTCR, PDC_TXTEN);
00379     }
00380 
00381     /* Determine the number of words of the expected response. */
00382     switch (cmd & MCI_RSPTYP) {
00383     case MCI_RSPTYP_48:
00384         rl = 2;
00385         break;
00386     case MCI_RSPTYP_136:
00387         rl = 4;
00388         break;
00389     default:
00390         rl = 0;
00391         break;
00392     }
00393     /* Wait for MCI_CMDRDY, MCI_ENDRX or MCI_BLKE. */
00394     while (((sr = inr(MCI_SR)) & wfs) == 0);
00395     /* Check for error. */
00396     if (sr & ces) {
00397         return sr;
00398     }
00399     /* Read the resonse. */
00400     for (i = 0; i < rl; i++) {
00401         ifc->ifc_resp[i] = inr(MCI_RSPR);
00402     }
00403 #ifdef NUTDEBUG
00404     printf("[Sta=%lx]", sr);
00405     if (rl) {
00406         printf("[Rsp");
00407         for (i = 0; i < rl; i++) {
00408             printf(" %lx", ifc->ifc_resp[i]);
00409         }
00410         putchar(']');
00411     }
00412     putchar('\n');
00413 #endif
00414     /* When writing, wait until the card is not busy. */
00415     if (wfs & MCI_BLKE) {
00416         while ((inr(MCI_SR) & MCI_NOTBUSY) == 0);
00417     }
00418     /* Do we need this? */
00419     ifc->ifc_buff = NULL;
00420 
00421     return sr;
00422 }
00423 
00434 static int At91MciDiscover(MCIFC * ifc)
00435 {
00436     uint32_t sr;
00437     uint32_t clk = MCI_MMC_BITRATE;
00438     uint32_t opd = 0;
00439     int tmo;
00440 
00441     At91MciEnablePins();
00442 
00443     /* Put all cards in idle state. */
00444     At91MciTxCmd(ifc, MCICMD_GO_IDLE_STATE | MCI_SPCMD_INIT, 0);
00445     At91MciTxCmd(ifc, MCICMD_GO_IDLE_STATE, 0);
00446 
00447     /* Poll SDC operating conditions. */
00448     for (tmo = 1000; --tmo;) {
00449         sr = At91MciTxCmd(ifc, MCICMD_SEND_APP_CMD, 0);
00450         if ((ifc->ifc_resp[0] & (1 << 8)) != 0 && (sr & MCICMD_IERROR) == 0) {
00451             sr = At91MciTxCmd(ifc, MCICMD_SEND_APP_OP_COND, MMCARD_VRANGE);
00452             if ((sr & MCICMD_IERROR) == 0) {
00453                 ifc->ifc_opcond = ifc->ifc_resp[0];
00454                 if (ifc->ifc_resp[0] & MMCOP_NBUSY) {
00455                     ifc->ifc_config |= MCIFLG_SDCARD;
00456                     break;
00457                 }
00458             }
00459         }
00460         NutSleep(1);
00461     }
00462 
00463     if (tmo == 0) {
00464         /* No SDC. Put all cards back in idle state and try MMC. */
00465         opd = MCI_OPDCMD;
00466         At91MciTxCmd(ifc, MCICMD_GO_IDLE_STATE, 0);
00467 
00468         /* Poll MMC operating conditions. */
00469         for (tmo = 100; --tmo;) {
00470             sr = At91MciTxCmd(ifc, MCICMD_SEND_OP_COND | opd, MMCARD_VRANGE);
00471             ifc->ifc_opcond = ifc->ifc_resp[0];
00472             if (ifc->ifc_resp[0] & MMCOP_NBUSY) {
00473                 break;
00474             }
00475             NutSleep(1);
00476         }
00477     }
00478 
00479     if (tmo == 0) {
00480         /* No valid card. */
00481         At91MciDisablePins();
00482         return -1;
00483     }
00484 
00485     /* Discover cards. */
00486     ifc->ifc_reladdr = 0;
00487     for (tmo = 50; --tmo;) {
00488         sr = At91MciTxCmd(ifc, MCICMD_ALL_SEND_CID | opd, 0);
00489         memcpy(ifc->ifc_cid, ifc->ifc_resp, sizeof(ifc->ifc_cid));
00490         if (sr & MCI_RTOE) {
00491             /* No more cards. */
00492             break;
00493         }
00494         if (ifc->ifc_config & MCIFLG_SDCARD) {
00495             /* SD Card will send an address. */
00496             ifc->ifc_reladdr = 0;
00497         } else {
00498             /* MultiMedia Card will receive an address. */
00499             ifc->ifc_reladdr++;
00500         }
00501         At91MciTxCmd(ifc, MCICMD_SEND_RELATIVE_ADDR | opd, ifc->ifc_reladdr << 16);
00502         if (ifc->ifc_config & MCIFLG_SDCARD) {
00503             /* Store SD Card address. */
00504             ifc->ifc_reladdr = ifc->ifc_resp[0] >> 16;
00505             /* SD Cards can run at higher clock rates. */
00506             clk = MCI_SDC_BITRATE;
00507         }
00508     }
00509 
00510     At91MciDisablePins();
00511     if (ifc->ifc_reladdr) {
00512         /* Switch to high speed transfer. */
00513         outr(MCI_MR, (inr(MCI_MR) & ~MCI_CLKDIV) | (At91MciClockDiv(clk) << MCI_CLKDIV_LSB));
00514         return 0;
00515     }
00516     return -1;
00517 }
00518 
00528 static int At91MciReadSingle(MCIFC * ifc, uint32_t blk, uint8_t * buf)
00529 {
00530     int rc = -1;
00531     uint32_t sr;
00532 
00533     /* Gain mutex access. */
00534     NutEventWait(&mutex, 0);
00535     At91MciEnablePins();
00536 
00537     sr = At91MciTxCmd(ifc, MCICMD_SELECT_CARD, ifc->ifc_reladdr << 16);
00538     if ((sr & MCICMD_ERROR) == 0) {
00539         sr = At91MciTxCmd(ifc, MCICMD_SET_BLOCKLEN, MMC_BLOCK_SIZE);
00540         if ((sr & MCICMD_ERROR) == 0) {
00541             ifc->ifc_buff = buf;
00542             sr = At91MciTxCmd(ifc, MCICMD_READ_SINGLE_BLOCK, blk * MMC_BLOCK_SIZE);
00543             if ((sr & MCICMD_ERROR) == 0) {
00544                 rc = 0;
00545             }
00546         }
00547         At91MciTxCmd(ifc, MCICMD_DESELECT_CARD, 0);
00548     }
00549 
00550     /* Release mutex access. */
00551     At91MciDisablePins();
00552     NutEventPost(&mutex);
00553 
00554     return rc;
00555 }
00556 
00566 static int At91MciWriteSingle(MCIFC * ifc, uint32_t blk, CONST uint8_t * buf)
00567 {
00568     int rc = -1;
00569     uint32_t sr;
00570 
00571     /* Gain mutex access. */
00572     NutEventWait(&mutex, 0);
00573     At91MciEnablePins();
00574 
00575     sr = At91MciTxCmd(ifc, MCICMD_SELECT_CARD, ifc->ifc_reladdr << 16);
00576     if ((sr & MCICMD_ERROR) == 0) {
00577         sr = At91MciTxCmd(ifc, MCICMD_SET_BLOCKLEN, MMC_BLOCK_SIZE);
00578         if ((sr & MCICMD_ERROR) == 0) {
00579             ifc->ifc_buff = (uint8_t *)buf;
00580             sr = At91MciTxCmd(ifc, MCICMD_WRITE_BLOCK, blk * MMC_BLOCK_SIZE);
00581             if ((sr & MCICMD_ERROR) == 0) {
00582                 rc = 0;
00583             }
00584         }
00585         At91MciTxCmd(ifc, MCICMD_DESELECT_CARD, 0);
00586     }
00587 
00588     /* Release mutex access. */
00589     At91MciDisablePins();
00590     NutEventPost(&mutex);
00591 
00592     return rc;
00593 }
00594 
00607 static int At91MciBlockRead(NUTFILE * nfp, void *buffer, int num)
00608 {
00609     MCIFCB *fcb = (MCIFCB *) nfp->nf_fcb;
00610     uint32_t blk = fcb->fcb_blknum;
00611     NUTDEVICE *dev = (NUTDEVICE *) nfp->nf_dev;
00612     MCIFC *ifc = (MCIFC *) dev->dev_icb;
00613     int rt;
00614 
00615     if (buffer == 0) {
00616         buffer = fcb->fcb_blkbuf;
00617     }
00618     blk += fcb->fcb_part.part_sect_offs;
00619 
00620     for (rt = 10; --rt >= 0;) {
00621         if (At91MciReadSingle(ifc, blk, buffer) == 0) {
00622             return 1;
00623         }
00624         At91MciReset(0);
00625     }
00626     return -1;
00627 }
00628 
00641 static int At91MciBlockWrite(NUTFILE * nfp, CONST void *buffer, int num)
00642 {
00643     MCIFCB *fcb = (MCIFCB *) nfp->nf_fcb;
00644     uint32_t blk = fcb->fcb_blknum;
00645     NUTDEVICE *dev = (NUTDEVICE *) nfp->nf_dev;
00646     MCIFC *ifc = (MCIFC *) dev->dev_icb;
00647 
00648     if (buffer == 0) {
00649         buffer = fcb->fcb_blkbuf;
00650     }
00651     blk += fcb->fcb_part.part_sect_offs;
00652 
00653     if (At91MciWriteSingle(ifc, blk, buffer) == 0) {
00654         return 1;
00655     }
00656     return -1;
00657 }
00658 
00667 static int At91MciUnmount(NUTFILE * nfp)
00668 {
00669     int rc = -1;
00670 
00671     if (nfp) {
00672         MCIFCB *fcb = (MCIFCB *) nfp->nf_fcb;
00673 
00674         if (fcb) {
00675             rc = fcb->fcb_fsdev->dev_ioctl(fcb->fcb_fsdev, FS_VOL_UNMOUNT, NULL);
00676             NutHeapFree(fcb);
00677         }
00678         NutHeapFree(nfp);
00679     }
00680     return rc;
00681 }
00682 
00708 static NUTFILE *At91MciMount(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00709 {
00710     int partno = 0;
00711     int i;
00712     NUTDEVICE *fsdev;
00713     NUTFILE *nfp;
00714     MCIFCB *fcb;
00715     DOSPART *part;
00716     MCIFC *ifc = (MCIFC *) dev->dev_icb;
00717     FSCP_VOL_MOUNT mparm;
00718 
00719     if (At91MciDiscover(ifc)) {
00720         errno = ENODEV;
00721         return NUTFILE_EOF;
00722     }
00723 
00724     /* Parse the name for a partition number and a file system driver. */
00725     if (*name) {
00726         partno = atoi(name);
00727         do {
00728             name++;
00729         } while (*name && *name != '/');
00730         if (*name == '/') {
00731             name++;
00732         }
00733     }
00734 #ifdef NUTDEBUG
00735     printf("['%s'-PART%d]", name, partno);
00736 #endif
00737 
00738     /*
00739      * Check the list of registered devices for the given name of the
00740      * files system driver. If none has been specified, get the first
00741      * file system driver in the list. Hopefully the application
00742      * registered one only.
00743      */
00744     for (fsdev = nutDeviceList; fsdev; fsdev = fsdev->dev_next) {
00745         if (*name == 0) {
00746             if (fsdev->dev_type == IFTYP_FS) {
00747                 break;
00748             }
00749         } else if (strcmp(fsdev->dev_name, name) == 0) {
00750             break;
00751         }
00752     }
00753 
00754     if (fsdev == 0) {
00755 #ifdef NUTDEBUG
00756         printf("[No FSDriver]");
00757 #endif
00758         errno = ENODEV;
00759         return NUTFILE_EOF;
00760     }
00761 
00762     if ((fcb = NutHeapAllocClear(sizeof(MCIFCB))) == 0) {
00763         errno = ENOMEM;
00764         return NUTFILE_EOF;
00765     }
00766     fcb->fcb_fsdev = fsdev;
00767 
00768     /* Initialize MMC access mutex semaphore. */
00769     NutEventPost(&mutex);
00770 
00771     /* Read MBR. */
00772     if (At91MciReadSingle(ifc, 0, fcb->fcb_blkbuf)) {
00773         NutHeapFree(fcb);
00774         return NUTFILE_EOF;
00775     }
00776     /* Check for the cookie at the end of this sector. */
00777     if (fcb->fcb_blkbuf[DOSPART_MAGICPOS] != 0x55 || fcb->fcb_blkbuf[DOSPART_MAGICPOS + 1] != 0xAA) {
00778         NutHeapFree(fcb);
00779         return NUTFILE_EOF;
00780     }
00781 
00782     /* Check for the partition table. */
00783     if(fcb->fcb_blkbuf[DOSPART_TYPEPOS] == 'F' &&
00784        fcb->fcb_blkbuf[DOSPART_TYPEPOS + 1] == 'A' &&
00785        fcb->fcb_blkbuf[DOSPART_TYPEPOS + 2] == 'T') {
00786         /* No partition table. Assume FAT12 and 32MB size. */
00787         fcb->fcb_part.part_type = PTYPE_FAT12;
00788         fcb->fcb_part.part_sect_offs = 0;
00789         fcb->fcb_part.part_sects = 65536; /* How to find out? */
00790     }
00791     else {
00792         /* Read partition table. */
00793         part = (DOSPART *) & fcb->fcb_blkbuf[DOSPART_SECTORPOS];
00794         for (i = 1; i <= 4; i++) {
00795             if (partno) {
00796                 if (i == partno) {
00797                     /* Found specified partition number. */
00798                     fcb->fcb_part = *part;
00799                     break;
00800                 }
00801             } else if (part->part_state & 0x80) {
00802                 /* Located first active partition. */
00803                 fcb->fcb_part = *part;
00804                 break;
00805             }
00806             part++;
00807         }
00808 
00809         if (fcb->fcb_part.part_type == PTYPE_EMPTY) {
00810             NutHeapFree(fcb);
00811             return NUTFILE_EOF;
00812         }
00813     }
00814     if ((nfp = NutHeapAlloc(sizeof(NUTFILE))) == 0) {
00815         NutHeapFree(fcb);
00816         errno = ENOMEM;
00817         return NUTFILE_EOF;
00818     }
00819     nfp->nf_next = 0;
00820     nfp->nf_dev = dev;
00821     nfp->nf_fcb = fcb;
00822 
00823     /*
00824      * Mount the file system volume.
00825      */
00826     mparm.fscp_bmnt = nfp;
00827     mparm.fscp_part_type = fcb->fcb_part.part_type;
00828     if (fsdev->dev_ioctl(fsdev, FS_VOL_MOUNT, &mparm)) {
00829         At91MciUnmount(nfp);
00830         return NUTFILE_EOF;
00831     }
00832     return nfp;
00833 }
00834 
00858 static int At91MciIOCtrl(NUTDEVICE * dev, int req, void *conf)
00859 {
00860     int rc = 0;
00861     MCIFC *ifc = (MCIFC *) dev->dev_icb;
00862 
00863     switch (req) {
00864     case NUTBLKDEV_MEDIAAVAIL:
00865         *((int *) conf) = 1;
00866         break;
00867     case NUTBLKDEV_MEDIACHANGE:
00868         *((int *) conf) = 0;
00869         break;
00870     case NUTBLKDEV_INFO:
00871         {
00872             BLKPAR_INFO *par = (BLKPAR_INFO *) conf;
00873             MCIFCB *fcb = (MCIFCB *) par->par_nfp->nf_fcb;
00874 
00875             par->par_nblks = fcb->fcb_part.part_sects;
00876             par->par_blksz = MMC_BLOCK_SIZE;
00877             par->par_blkbp = fcb->fcb_blkbuf;
00878         }
00879         break;
00880     case NUTBLKDEV_SEEK:
00881         {
00882             BLKPAR_SEEK *par = (BLKPAR_SEEK *) conf;
00883             MCIFCB *fcb = (MCIFCB *) par->par_nfp->nf_fcb;
00884 
00885             fcb->fcb_blknum = par->par_blknum;
00886         }
00887         break;
00888     case MMCARD_GETOCR:
00889         *((uint32_t *) conf) = ifc->ifc_opcond;
00890         break;
00891     default:
00892         rc = -1;
00893         break;
00894     }
00895     return rc;
00896 }
00897 
00898 static MCIFC mci0_info;
00899 
00912 NUTDEVICE devAt91Mci0 = {
00913     0,                          
00914     {'M', 'C', 'I', '0', 0, 0, 0, 0, 0}
00915     ,                           
00916     0,                          
00917     0,                          
00918     0,                          
00919     &mci0_info,                 
00920     0,                          
00921     At91MciInit,                
00922     At91MciIOCtrl,              
00923     At91MciBlockRead,           
00924     At91MciBlockWrite,          
00925     At91MciMount,               
00926     At91MciUnmount,             
00927     0                           
00928 };
00929