at91_mci.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 by egnite Software GmbH.
00003  * Copyright (C) 2008 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 
00062 #include <errno.h>
00063 #include <string.h>
00064 #include <stdlib.h>
00065 
00066 #include <sys/heap.h>
00067 #include <sys/timer.h>
00068 #include <sys/event.h>
00069 #include <fs/dospart.h>
00070 #include <fs/fs.h>
00071 
00072 #include <dev/blockdev.h>
00073 #include <dev/mmcard.h>
00074 #include <dev/at91_mci.h>
00075 
00076 
00077 #if 0
00078 /* Use for local debugging. */
00079 #define NUTDEBUG
00080 #include <stdio.h>
00081 #endif
00082 
00087 
00088 #ifndef MMC_BLOCK_SIZE
00089 #define MMC_BLOCK_SIZE  512
00090 #endif
00091 
00092 #ifndef MMC_PINS_A
00093 #define MMC_PINS_A  _BV(PA8_MCCK_A)
00094 #endif
00095 
00096 #ifndef MMC_PINS_B
00097 #define MMC_PINS_B  _BV(PA1_MCCDB_B) | _BV(PA0_MCDB0_B) | _BV(PA5_MCDB1_B) | _BV(PA4_MCDB2_B) | _BV(PA3_MCDB3_B)
00098 #endif
00099 
00100 #define MCICMD_ALL_SEND_CID         (MMCMD_ALL_SEND_CID | MCI_OPDCMD | MCI_MAXLAT | MCI_RSPTYP_136)
00101 #define MCICMD_DESELECT_CARD        (MMCMD_SELECT_CARD)
00102 #define MCICMD_GO_IDLE_STATE        (MMCMD_GO_IDLE_STATE)
00103 #define MCICMD_READ_SINGLE_BLOCK    (MMCMD_READ_SINGLE_BLOCK | MCI_TRCMD_START | MCI_TRDIR | MCI_MAXLAT | MCI_RSPTYP_48)
00104 #define MCICMD_SELECT_CARD          (MMCMD_SELECT_CARD | MCI_MAXLAT | MCI_RSPTYP_48)
00105 #define MCICMD_SEND_APP_CMD         (MMCMD_SEND_APP_CMD | MCI_MAXLAT | MCI_RSPTYP_48)
00106 #define MCICMD_SEND_APP_OP_COND     (MMCMD_SEND_APP_OP_COND | MCI_MAXLAT | MCI_RSPTYP_48)
00107 #define MCICMD_SEND_OP_COND         (MMCMD_SEND_OP_COND | MCI_MAXLAT | MCI_RSPTYP_48)
00108 #define MCICMD_SEND_RELATIVE_ADDR   (MMCMD_SEND_RELATIVE_ADDR | MCI_MAXLAT | MCI_RSPTYP_48)
00109 #define MCICMD_SEND_STATUS          (MMCMD_SEND_STATUS | MCI_MAXLAT | MCI_RSPTYP_48)
00110 #define MCICMD_SET_BLOCKLEN         (MMCMD_SET_BLOCKLEN | MCI_MAXLAT | MCI_RSPTYP_48)
00111 #define MCICMD_WRITE_BLOCK          (MMCMD_WRITE_BLOCK | MCI_TRCMD_START | MCI_MAXLAT | MCI_RSPTYP_48)
00112 
00113 
00114 #define MCICMD_ERROR    (MCI_UNRE | MCI_OVRE | MCI_DTOE | MCI_DCRCE | MCI_RTOE | MCI_RENDE | MCI_RCRCE | MCI_RDIRE | MCI_RINDE)
00115 
00116 #define MCIFLG_SDCARD   0x00000001
00117 #define MCIFLG_4BIT     0x00000010
00118 
00122 typedef struct _MCIFC {
00124     uint32_t ifc_config;
00126     uint32_t ifc_opcond;
00128     uint32_t ifc_reladdr;
00130     uint8_t *ifc_buff;
00132     uint32_t ifc_resp[4];
00134     uint32_t ifc_cid[4];
00135 } MCIFC;
00136 
00140 typedef struct _MCIFCB {
00143     NUTDEVICE *fcb_fsdev;
00144 
00147     DOSPART fcb_part;
00148 
00156     uint32_t fcb_blknum;
00157 
00167     uint8_t fcb_blkbuf[MMC_BLOCK_SIZE];
00168 } MCIFCB;
00169 
00170 /*
00171  * Several routines call NutSleep, which results in a context switch.
00172  * This mutual exclusion semaphore takes care, that multiple threads
00173  * do not interfere with each other.
00174  */
00175 static HANDLE mutex;
00176 
00183 static void At91MciReset(int init)
00184 {
00185     uint32_t mode;
00186     uint32_t dtmo;
00187     uint32_t slot;
00188 
00189     /* Enable MCI clock. */
00190     outr(PMC_PCER, _BV(MCI_ID));
00191 
00192     if (init) {
00193         outr(MCI_IDR, 0xFFFFFFFF);
00194         /* Set initial configuration. */
00195         dtmo = MCI_DTOMUL_1M | MCI_DTOCYC;
00196         /* Slow start: MMC clock is MCK / (2 * (CLKDIV + 1)) */
00197         mode = MCI_RDPROOF | MCI_WRPROOF | MCI_PDCMODE | (2 << MCI_PWSDIV_LSB) | (128 << MCI_CLKDIV_LSB);
00198         slot = MCI_SDCSEL_SLOTB;
00199     } else {
00200         /* Retrieve current configuration. */
00201         dtmo = inr(MCI_DTOR);
00202         mode = inr(MCI_MR) & 0xffff;
00203         slot = inr(MCI_SDCR);
00204     }
00205 
00206     /* Disable and software reset. */
00207     outr(MCI_CR, MCI_MCIDIS | MCI_SWRST);
00208 
00209     /* Set configuration values. */
00210     outr(MCI_DTOR, dtmo);
00211     outr(MCI_MR, mode);
00212     outr(MCI_SDCR, slot);
00213 
00214     /* Enable card interface. */
00215     outr(MCI_CR, MCI_MCIEN | MCI_PWSEN);
00216 }
00217 
00226 static int At91MciInit(NUTDEVICE * dev)
00227 {
00228     /* Disable PIO lines used for MCI. */
00229     outr(PIOA_PDR, MMC_PINS_A | MMC_PINS_B);
00230     /* Enable peripherals. */
00231     outr(PIOA_ASR, MMC_PINS_A);
00232     outr(PIOA_BSR, MMC_PINS_B);
00233     /* Initialize the MCI hardware. */
00234     At91MciReset(1);
00235 
00236     return 0;
00237 }
00238 
00248 static uint32_t At91MciTxCmd(MCIFC * ifc, uint32_t cmd, uint32_t param)
00249 {
00250     uint32_t sr;
00251     uint32_t rl;
00252     uint32_t i;
00253     uint32_t wfs = MCI_CMDRDY;
00254 
00255     /*
00256      * Disable PDC.
00257      */
00258 #ifdef NUTDEBUG
00259     printf("[Cmd%lu,%lx]", cmd & MCI_CMDNB, param);
00260 #endif
00261     outr(MCI_PTCR, PDC_TXTDIS | PDC_RXTDIS);
00262     outr(MCI_MR, inr(MCI_MR) & ~(MCI_BLKLEN | MCI_PDCMODE));
00263     outr(MCI_RCR, 0);
00264     outr(MCI_RNCR, 0);
00265     outr(MCI_TCR, 0);
00266     outr(MCI_TNCR, 0);
00267 
00268     if (cmd & MCI_TRCMD_START) {
00269         /* Data transfer. Make sure that the buffer is set. */
00270         if (ifc->ifc_buff == NULL) {
00271             errno = EINVAL;
00272             return MCI_OVRE | MCI_UNRE;
00273         }
00274         /* Set block length and PDC mode. */
00275         outr(MCI_MR, (inr(MCI_MR) & ~MCI_BLKLEN) | (MMC_BLOCK_SIZE << MCI_BLKLEN_LSB) | MCI_PDCMODE);
00276         if (cmd & MCI_TRDIR) {
00277             /* Set PDC address and counter for reading. */
00278             outr(MCI_RPR, (uint32_t) ifc->ifc_buff);
00279             outr(MCI_RCR, MMC_BLOCK_SIZE / 4);
00280             /* Enable PDC read. */
00281             outr(MCI_PTCR, PDC_RXTEN);
00282             /* We will wait until end of data transmission. */
00283             wfs = MCI_ENDRX;
00284         } else {
00285             /* Set PDC address and counter for writing. */
00286             outr(MCI_TPR, (uint32_t) ifc->ifc_buff);
00287             outr(MCI_TCR, MMC_BLOCK_SIZE / 4);
00288             /* We will wait until data block ended. */
00289             wfs = MCI_BLKE;
00290         }
00291     }
00292     /* Set card parameter and command. */
00293     outr(MCI_ARGR, param);
00294     outr(MCI_CMDR, cmd);
00295 
00296     /* When writing, enable PDC after sending the command. */
00297     if ((cmd & (MCI_TRCMD_START | MCI_TRDIR)) == MCI_TRCMD_START) {
00298         outr(MCI_PTCR, PDC_TXTEN);
00299     }
00300 
00301     /* Determine the number of words of the expected response. */
00302     switch (cmd & MCI_RSPTYP) {
00303     case MCI_RSPTYP_48:
00304         rl = 2;
00305         break;
00306     case MCI_RSPTYP_136:
00307         rl = 4;
00308         break;
00309     default:
00310         rl = 0;
00311         break;
00312     }
00313     /* Wait for MCI_CMDRDY, MCI_ENDRX or MCI_BLKE. */
00314     while (((sr = inr(MCI_SR)) & wfs) == 0);
00315     /* Read the resonse. */
00316     for (i = 0; i < rl; i++) {
00317         ifc->ifc_resp[i] = inr(MCI_RSPR);
00318     }
00319 #ifdef NUTDEBUG
00320     printf("[Sta=%lx][Rsp", sr);
00321     for (i = 0; i < rl; i++) {
00322         printf(" %lx", ifc->ifc_resp[i]);
00323     }
00324     printf("]\n");
00325 #endif
00326     /* When writing, wait until the card is not busy. */
00327     if (wfs & MCI_BLKE) {
00328         while ((inr(MCI_SR) & MCI_NOTBUSY) == 0);
00329     }
00330     /* Do we need this? */
00331     ifc->ifc_buff = NULL;
00332 
00333     return sr;
00334 }
00335 
00336 
00347 static int At91MciDiscover(MCIFC * ifc)
00348 {
00349     uint32_t sr;
00350     int tmo;
00351 
00352     /* Put all cards in idle state. */
00353     At91MciTxCmd(ifc, MCICMD_GO_IDLE_STATE, 0);
00354     NutSleep(10);
00355 
00356     /* Poll SDC operating conditions. */
00357     for (tmo = 100; --tmo;) {
00358         At91MciTxCmd(ifc, MCICMD_SEND_APP_CMD, 0);
00359         sr = At91MciTxCmd(ifc, MCICMD_SEND_APP_OP_COND, MMCARD_32_33V | MMCARD_31_32V | MMCARD_30_31V);
00360         ifc->ifc_opcond = ifc->ifc_resp[0];
00361         if (ifc->ifc_resp[0] & MMCOP_NBUSY) {
00362             ifc->ifc_config |= MCIFLG_SDCARD;
00363             break;
00364         }
00365     }
00366 
00367     if (tmo == 0) {
00368         /* No SDC. Put all cards back in idle state and try MMC. */
00369         At91MciTxCmd(ifc, MCICMD_GO_IDLE_STATE, 0);
00370         NutSleep(10);
00371 
00372         /* Poll MMC operating conditions. */
00373         for (tmo = 100; --tmo;) {
00374             sr = At91MciTxCmd(ifc, MCICMD_SEND_OP_COND, MMCARD_32_33V | MMCARD_31_32V | MMCARD_30_31V);
00375             ifc->ifc_opcond = ifc->ifc_resp[0];
00376             if (ifc->ifc_resp[0] & MMCOP_NBUSY) {
00377                 break;
00378             }
00379         }
00380     }
00381 
00382     if (tmo == 0) {
00383         /* No valid card. */
00384         return -1;
00385     }
00386 
00387     /* Discover cards. */
00388     ifc->ifc_reladdr = 0;
00389     for (tmo = 500; --tmo;) {
00390         sr = At91MciTxCmd(ifc, MCICMD_ALL_SEND_CID, 0);
00391         memcpy(ifc->ifc_cid, ifc->ifc_resp, sizeof(ifc->ifc_cid));
00392         if (sr & MCI_RTOE) {
00393             /* No more cards. */
00394             break;
00395         }
00396         if (ifc->ifc_config & MCIFLG_SDCARD) {
00397             /* SD Card will send an address. */
00398             ifc->ifc_reladdr = 0;
00399         } else {
00400             /* MultiMedia Card will receive an address. */
00401             ifc->ifc_reladdr++;
00402         }
00403         At91MciTxCmd(ifc, MCICMD_SEND_RELATIVE_ADDR, ifc->ifc_reladdr << 16);
00404         if (ifc->ifc_config & MCIFLG_SDCARD) {
00405             /* Store SD Card address. */
00406             ifc->ifc_reladdr = ifc->ifc_resp[0] >> 16;
00407         }
00408     }
00409 
00410     /* Switch to high speed transfer. */
00411     outr(MCI_MR, MCI_PDCMODE | (2 << MCI_PWSDIV_LSB) | (16 << MCI_CLKDIV_LSB));
00412 
00413     return ifc->ifc_reladdr ? 0 : -1;
00414 }
00415 
00425 static int At91MciReadSingle(MCIFC * ifc, uint32_t blk, uint8_t * buf)
00426 {
00427     int rc = -1;
00428     uint32_t sr;
00429 
00430     /* Gain mutex access. */
00431     NutEventWait(&mutex, 0);
00432 
00433     sr = At91MciTxCmd(ifc, MCICMD_SELECT_CARD, ifc->ifc_reladdr << 16);
00434     if ((sr & MCICMD_ERROR) == 0) {
00435         sr = At91MciTxCmd(ifc, MCICMD_SET_BLOCKLEN, MMC_BLOCK_SIZE);
00436         if ((sr & MCICMD_ERROR) == 0) {
00437             ifc->ifc_buff = buf;
00438             sr = At91MciTxCmd(ifc, MCICMD_READ_SINGLE_BLOCK, blk * MMC_BLOCK_SIZE);
00439             if ((sr & MCICMD_ERROR) == 0) {
00440                 rc = 0;
00441             }
00442         }
00443         At91MciTxCmd(ifc, MCICMD_DESELECT_CARD, 0);
00444     }
00445 
00446     /* Release mutex access. */
00447     NutEventPost(&mutex);
00448 
00449     return rc;
00450 }
00451 
00461 static int At91MciWriteSingle(MCIFC * ifc, uint32_t blk, CONST uint8_t * buf)
00462 {
00463     int rc = -1;
00464     uint32_t sr;
00465 
00466     /* Gain mutex access. */
00467     NutEventWait(&mutex, 0);
00468 
00469     sr = At91MciTxCmd(ifc, MCICMD_SELECT_CARD, ifc->ifc_reladdr << 16);
00470     if ((sr & MCICMD_ERROR) == 0) {
00471         sr = At91MciTxCmd(ifc, MCICMD_SET_BLOCKLEN, MMC_BLOCK_SIZE);
00472         if ((sr & MCICMD_ERROR) == 0) {
00473             ifc->ifc_buff = (uint8_t *)buf;
00474             sr = At91MciTxCmd(ifc, MCICMD_WRITE_BLOCK, blk * MMC_BLOCK_SIZE);
00475             if ((sr & MCICMD_ERROR) == 0) {
00476                 rc = 0;
00477             }
00478         }
00479         At91MciTxCmd(ifc, MCICMD_DESELECT_CARD, 0);
00480     }
00481 
00482     /* Release mutex access. */
00483     NutEventPost(&mutex);
00484 
00485     return rc;
00486 }
00487 
00500 static int At91MciBlockRead(NUTFILE * nfp, void *buffer, int num)
00501 {
00502     MCIFCB *fcb = (MCIFCB *) nfp->nf_fcb;
00503     uint32_t blk = fcb->fcb_blknum;
00504     NUTDEVICE *dev = (NUTDEVICE *) nfp->nf_dev;
00505     MCIFC *ifc = (MCIFC *) dev->dev_icb;
00506     int rt;
00507 
00508     if (buffer == 0) {
00509         buffer = fcb->fcb_blkbuf;
00510     }
00511     blk += fcb->fcb_part.part_sect_offs;
00512 
00513     for (rt = 10; --rt >= 0;) {
00514         if (At91MciReadSingle(ifc, blk, buffer) == 0) {
00515             return 1;
00516         }
00517         At91MciReset(0);
00518     }
00519     return -1;
00520 }
00521 
00534 static int At91MciBlockWrite(NUTFILE * nfp, CONST void *buffer, int num)
00535 {
00536     MCIFCB *fcb = (MCIFCB *) nfp->nf_fcb;
00537     uint32_t blk = fcb->fcb_blknum;
00538     NUTDEVICE *dev = (NUTDEVICE *) nfp->nf_dev;
00539     MCIFC *ifc = (MCIFC *) dev->dev_icb;
00540 
00541     if (buffer == 0) {
00542         buffer = fcb->fcb_blkbuf;
00543     }
00544     blk += fcb->fcb_part.part_sect_offs;
00545 
00546     if (At91MciWriteSingle(ifc, blk, buffer) == 0) {
00547         return 1;
00548     }
00549     return -1;
00550 }
00551 
00560 static int At91MciUnmount(NUTFILE * nfp)
00561 {
00562     int rc = -1;
00563 
00564     if (nfp) {
00565         MCIFCB *fcb = (MCIFCB *) nfp->nf_fcb;
00566 
00567         if (fcb) {
00568             rc = fcb->fcb_fsdev->dev_ioctl(fcb->fcb_fsdev, FS_VOL_UNMOUNT, NULL);
00569             NutHeapFree(fcb);
00570         }
00571         NutHeapFree(nfp);
00572     }
00573     return rc;
00574 }
00575 
00601 static NUTFILE *At91MciMount(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00602 {
00603     int partno = 0;
00604     int i;
00605     NUTDEVICE *fsdev;
00606     NUTFILE *nfp;
00607     MCIFCB *fcb;
00608     DOSPART *part;
00609     MCIFC *ifc = (MCIFC *) dev->dev_icb;
00610     FSCP_VOL_MOUNT mparm;
00611 
00612     if (At91MciDiscover(ifc)) {
00613         errno = ENODEV;
00614         return NUTFILE_EOF;
00615     }
00616 
00617     /* Parse the name for a partition number and a file system driver. */
00618     if (*name) {
00619         partno = atoi(name);
00620         do {
00621             name++;
00622         } while (*name && *name != '/');
00623         if (*name == '/') {
00624             name++;
00625         }
00626     }
00627 #ifdef NUTDEBUG
00628     printf("['%s'-PART%d]", name, partno);
00629 #endif
00630 
00631     /*
00632      * Check the list of registered devices for the given name of the
00633      * files system driver. If none has been specified, get the first
00634      * file system driver in the list. Hopefully the application
00635      * registered one only.
00636      */
00637     for (fsdev = nutDeviceList; fsdev; fsdev = fsdev->dev_next) {
00638         if (*name == 0) {
00639             if (fsdev->dev_type == IFTYP_FS) {
00640                 break;
00641             }
00642         } else if (strcmp(fsdev->dev_name, name) == 0) {
00643             break;
00644         }
00645     }
00646 
00647     if (fsdev == 0) {
00648 #ifdef NUTDEBUG
00649         printf("[No FSDriver]");
00650 #endif
00651         errno = ENODEV;
00652         return NUTFILE_EOF;
00653     }
00654 
00655     if ((fcb = NutHeapAllocClear(sizeof(MCIFCB))) == 0) {
00656         errno = ENOMEM;
00657         return NUTFILE_EOF;
00658     }
00659     fcb->fcb_fsdev = fsdev;
00660 
00661     /* Initialize MMC access mutex semaphore. */
00662     NutEventPost(&mutex);
00663 
00664     /* Read MBR. */
00665     if (At91MciReadSingle(ifc, 0, fcb->fcb_blkbuf)) {
00666         NutHeapFree(fcb);
00667         return NUTFILE_EOF;
00668     }
00669     /* Check for the cookie at the end of this sector. */
00670     if (fcb->fcb_blkbuf[DOSPART_MAGICPOS] != 0x55 || fcb->fcb_blkbuf[DOSPART_MAGICPOS + 1] != 0xAA) {
00671         NutHeapFree(fcb);
00672         return NUTFILE_EOF;
00673     }
00674 
00675     /* Check for the partition table. */
00676     if(fcb->fcb_blkbuf[DOSPART_TYPEPOS] == 'F' && 
00677        fcb->fcb_blkbuf[DOSPART_TYPEPOS + 1] == 'A' &&
00678        fcb->fcb_blkbuf[DOSPART_TYPEPOS + 2] == 'T') {
00679         /* No partition table. Assume FAT12 and 32MB size. */
00680         fcb->fcb_part.part_type = PTYPE_FAT12;
00681         fcb->fcb_part.part_sect_offs = 0;
00682         fcb->fcb_part.part_sects = 65536; /* How to find out? */
00683     }
00684     else {
00685         /* Read partition table. */
00686         part = (DOSPART *) & fcb->fcb_blkbuf[DOSPART_SECTORPOS];
00687         for (i = 1; i <= 4; i++) {
00688             if (partno) {
00689                 if (i == partno) {
00690                     /* Found specified partition number. */
00691                     fcb->fcb_part = *part;
00692                     break;
00693                 }
00694             } else if (part->part_state & 0x80) {
00695                 /* Located first active partition. */
00696                 fcb->fcb_part = *part;
00697                 break;
00698             }
00699             part++;
00700         }
00701 
00702         if (fcb->fcb_part.part_type == PTYPE_EMPTY) {
00703             NutHeapFree(fcb);
00704             return NUTFILE_EOF;
00705         }
00706     }
00707     if ((nfp = NutHeapAlloc(sizeof(NUTFILE))) == 0) {
00708         NutHeapFree(fcb);
00709         errno = ENOMEM;
00710         return NUTFILE_EOF;
00711     }
00712     nfp->nf_next = 0;
00713     nfp->nf_dev = dev;
00714     nfp->nf_fcb = fcb;
00715 
00716     /*
00717      * Mount the file system volume.
00718      */
00719     mparm.fscp_bmnt = nfp;
00720     mparm.fscp_part_type = fcb->fcb_part.part_type;
00721     if (fsdev->dev_ioctl(fsdev, FS_VOL_MOUNT, &mparm)) {
00722         At91MciUnmount(nfp);
00723         return NUTFILE_EOF;
00724     }
00725     return nfp;
00726 }
00727 
00751 static int At91MciIOCtrl(NUTDEVICE * dev, int req, void *conf)
00752 {
00753     int rc = 0;
00754     MCIFC *ifc = (MCIFC *) dev->dev_icb;
00755 
00756     switch (req) {
00757     case NUTBLKDEV_MEDIAAVAIL:
00758         *((int *) conf) = 1;
00759         break;
00760     case NUTBLKDEV_MEDIACHANGE:
00761         *((int *) conf) = 0;
00762         break;
00763     case NUTBLKDEV_INFO:
00764         {
00765             BLKPAR_INFO *par = (BLKPAR_INFO *) conf;
00766             MCIFCB *fcb = (MCIFCB *) par->par_nfp->nf_fcb;
00767 
00768             par->par_nblks = fcb->fcb_part.part_sects;
00769             par->par_blksz = MMC_BLOCK_SIZE;
00770             par->par_blkbp = fcb->fcb_blkbuf;
00771         }
00772         break;
00773     case NUTBLKDEV_SEEK:
00774         {
00775             BLKPAR_SEEK *par = (BLKPAR_SEEK *) conf;
00776             MCIFCB *fcb = (MCIFCB *) par->par_nfp->nf_fcb;
00777 
00778             fcb->fcb_blknum = par->par_blknum;
00779         }
00780         break;
00781     case MMCARD_GETOCR:
00782         *((uint32_t *) conf) = ifc->ifc_opcond;
00783         break;
00784     default:
00785         rc = -1;
00786         break;
00787     }
00788     return rc;
00789 }
00790 
00791 static MCIFC mci0_info;
00792 
00805 NUTDEVICE devAt91Mci0 = {
00806     0,                          
00807     {'M', 'C', 'I', '0', 0, 0, 0, 0, 0}
00808     ,                           
00809     0,                          
00810     0,                          
00811     0,                          
00812     &mci0_info,                 
00813     0,                          
00814     At91MciInit,                
00815     At91MciIOCtrl,              
00816     At91MciBlockRead,           
00817     At91MciBlockWrite,          
00818     At91MciMount,               
00819     At91MciUnmount,             
00820     0                           
00821 };
00822 

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