| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003 |
- /*
- * Copyright (C) 2012 by Rob van Lieshout (info@pragmalab.nl)
- * Copyright (C) 2012 by Ole Reinhardt (ole.reinhardt@embedded-it.de)
- * Copyright (C) 2008 by egnite GmbH.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * For additional information see http://www.ethernut.de/
- */
- /*!
- * \brief Basic block device driver for multimedia cards.
- *
- * The driver uses SDIO mode, 4-bit bus
- *
- */
- #include <cfg/mmci.h>
- #include <errno.h>
- #include <string.h>
- #include <stdlib.h>
- #include <sys/heap.h>
- #include <sys/timer.h>
- #include <sys/event.h>
- #include <fs/dospart.h>
- #include <fs/fs.h>
- #include <dev/blockdev.h>
- #include "arch/cm3/nxp/lpc177x_8x_mmcard_sdio.h"
- #include "arch/cm3/nxp/lpc177x_8x_mci.h"
- #ifdef NUTDEBUG
- #include <stdio.h>
- #endif
- /*!
- * \addtogroup Card
- */
- /*@{*/
- typedef struct _MCIFC
- {
- uint32_t ifc_config; /*! \brief Configuration flags. */
- uint32_t ifc_opcond; /*! \brief Operating conditions. */
- uint32_t ifc_reladdr; /*! \brief Relative card address. */
- uint8_t *ifc_buff; /*! \brief Pointer to sector buffer. */
- uint32_t ifc_csd[4]; /*! \brief Card Specific Data CSD. */
- //uint32_t ifc_cid[4]; /*! \brief Card identification. */
- uint8_t ifc_admode; /*! \brief adressing mode */
- } MCIFC;
- /*!
- * \brief Local multimedia card mount information.
- */
- typedef struct _MMCFCB
- {
- /*! \brief Attached file system device.
- */
- NUTDEVICE *fcb_fsdev;
- /*! \brief Partition table entry of the currently mounted partition.
- */
- DOSPART fcb_part;
- /*! \brief Next block number to read.
- *
- * The file system driver will send a NUTBLKDEV_SEEK control command
- * to set this value before calling the read or the write routine.
- *
- * The number is partition relative.
- */
- uint32_t fcb_blknum;
- /*! \brief Internal block buffer.
- *
- * A file system driver may use this one or optionally provide it's
- * own buffers.
- *
- * Minimal systems may share their external bus interface with
- * device I/O lines, in which case the buffer must be located
- * in internal memory.
- */
- u_char fcb_blkbuf[MMC_BLOCK_SIZE];
- } MMCFCB;
- /* Flags to check whether a partition table is present or not */
- #define MBR_P_TABLE_PRESENT 0
- #define MBR_P_TABLE_NOT_PRESENT 1
- /*
- * Several routines call NutSleep, which results in a context switch.
- * This mutual exclusion semaphore takes care, that multiple threads
- * do not interfere with each other.
- */
- static HANDLE mutex;
- static MCIFC mci0_ifc;
- static st_Mci_CardId cidval;
- /* local routines */
- static uint32_t Lpc177x_8x_MmcardWriteData(uint8_t*, int, int);
- static uint32_t Lpc177x_8x_MmcardReadData(uint8_t*, int, int);
- static int Lpc177x_8x_MmcardUnmount(NUTFILE * nfp);
- #ifdef NUTDEBUG
- static void Lpc177x_8x_MmcardShowStatusBits(uint32_t);
- #endif
- /*-------------------------------------------------------------------------*/
- /* start of code */
- /*-------------------------------------------------------------------------*/
- #ifdef NUTDEBUG
- /************************************************************************//**
- * \brief Show status bits for MCI_status word
- *
- * \param None
- *
- * \return None
- ****************************************************************************/
- static void Lpc177x_8x_MmcardShowStatusBits(uint32_t MCIStatus)
- {
- if (MCIStatus & MCI_CMD_CRC_FAIL)
- {
- printf("MCI_CMD_CRC_FAIL\n");
- }
- if (MCIStatus & MCI_DATA_CRC_FAIL)
- {
- printf("MCI_DATA_CRC_FAIL\n");
- }
- if (MCIStatus & MCI_CMD_TIMEOUT)
- {
- printf("MCI_CMD_TIMEOUT\n");
- }
- if (MCIStatus & MCI_DATA_TIMEOUT)
- {
- printf("MCI_DATA_TIMEOUT\n");
- }
- if (MCIStatus & MCI_TX_UNDERRUN)
- {
- printf("MCI_TX_UNDERRUN\n");
- }
- if (MCIStatus & MCI_RX_OVERRUN)
- {
- printf("MCI_RX_OVERRUN\n");
- }
- if (MCIStatus & MCI_CMD_RESP_END)
- {
- printf("MCI_CMD_RESP_END\n");
- }
- if (MCIStatus & MCI_CMD_SENT)
- {
- printf("MCI_CMD_SENT\n");
- }
- if (MCIStatus & MCI_DATA_END)
- {
- printf("MCI_DATA_END\n");
- }
- if (MCIStatus & MCI_START_BIT_ERR)
- {
- printf("MCI_START_BIT_ERR\n");
- }
- if (MCIStatus & MCI_DATA_BLK_END)
- {
- printf("MCI_DATA_BLK_END\n");
- }
- if (MCIStatus & MCI_CMD_ACTIVE)
- {
- printf("MCI_CMD_ACTIVE\n");
- }
- if (MCIStatus & MCI_TX_ACTIVE)
- {
- printf("MCI_TX_ACTIVE\n");
- }
- if (MCIStatus & MCI_RX_ACTIVE)
- {
- printf("MCI_RX_ACTIVE\n");
- }
- if (MCIStatus & MCI_TX_HALF_EMPTY)
- {
- printf("MCI_TX_HALF_EMPTY\n");
- }
- if (MCIStatus & MCI_RX_HALF_FULL)
- {
- printf("MCI_RX_HALF_FULL\n");
- }
- if (MCIStatus & MCI_TX_FIFO_FULL)
- {
- printf("MCI_TX_FIFO_FULL\n");
- }
- if (MCIStatus & MCI_RX_FIFO_FULL)
- {
- printf("MCI_RX_FIFO_FULL\n");
- }
- if (MCIStatus & MCI_TX_FIFO_EMPTY)
- {
- printf("MCI_TX_FIFO_EMPTY\n");
- }
- if (MCIStatus & MCI_RX_FIFO_EMPTY)
- {
- printf("MCI_RX_FIFO_EMPTY\n");
- }
- if (MCIStatus & MCI_TX_DATA_AVAIL)
- {
- printf("MCI_TX_DATA_AVAIL\n");
- }
- if (MCIStatus & MCI_RX_DATA_AVAIL)
- {
- printf("MCI_RX_DATA_AVAIL\n");
- }
- }
- #endif
- /*!
- * \brief read n-blocks of data, starting at blocknum. Wait for ending!
- *
- * \param buffer Pointer to the data buffer to fill.
- * \param blk first blocknumber to read
- * \param num Maximum number of blocks to write. Please note the buffer
- * should be able to contain the data. No boundery test is performed
- *
- * \return A return value of <0 indicates an error.
- */
- static uint32_t Lpc177x_8x_MmcardReadData(uint8_t* buffer, int blk, int num)
- {
- int32_t retVal;
- uint32_t errorState;
- /* Gain mutex access. */
- NutEventWait(&mutex, 0);
- retVal = Lpc177x_8x_MciReadBlock(buffer, blk, num);
- if (retVal == MCI_FUNC_OK)
- {
- /*
- * Reading blocks have started, now wait till this job is finished
- * Please note the driver uses 16 word FIFO in the background to
- * transfer the data under interrupt from the card
- */
- while (Lpc177x_8x_MciGetDataXferEndState() != 0);
- errorState = Lpc177x_8x_MciGetXferErrState();
- if ((num > 1) || errorState)
- {
- Lpc177x_8x_MciCmd_StopTransmission();
- }
- if (errorState)
- {
- #ifdef NUTDEBUG
- printf("%s() failed\n", __FUNCTION__);
- Lpc177x_8x_MmcardShowStatusBits(errorState);
- #endif
- // perform 1 retry in case of an error
- retVal = Lpc177x_8x_MciReadBlock(buffer, blk, num);
- if (retVal == MCI_FUNC_OK)
- {
- /*
- * Reading blocks have started, now wait till this job is finished
- * Please note the driver uses 16 word FIFO in the background to
- * transfer the data under interrupt from the card
- */
- while (Lpc177x_8x_MciGetDataXferEndState() != 0);
- errorState = Lpc177x_8x_MciGetXferErrState();
- if ((num > 1) || errorState)
- {
- Lpc177x_8x_MciCmd_StopTransmission();
- }
- if (errorState)
- {
- #ifdef NUTDEBUG
- printf("%s() failed again\n", __FUNCTION__);
- Lpc177x_8x_MmcardShowStatusBits(errorState);
- #endif
- retVal = MCI_FUNC_FAILED;
- }
- }
- }
- }
- /* Release mutex access. */
- NutEventPost(&mutex);
- return(retVal);
- }
- /*!
- * \brief write n-blocks of data, starting at blocknum. Wait for ending!
- *
- * \param buffer Pointer to the data buffer to write from.
- * \param blk first blocknumber to write
- * \param num Maximum number of blocks to write.
- *
- * \return A return value of <0 indicates an error.
- */
- static uint32_t Lpc177x_8x_MmcardWriteData(uint8_t* buffer, int blk, int num)
- {
- int32_t retVal;
- uint32_t errorState;
- /* Gain mutex access. */
- NutEventWait(&mutex, 0);
- retVal = Lpc177x_8x_MciWriteBlock(buffer, blk, num);
- if (retVal == MCI_FUNC_OK)
- {
- /*
- * Writing blocks have started, now wait till this job is finished
- * Please note the driver uses 16 word FIFO in the background to
- * transfer the data under interrupt to the card
- */
- while (Lpc177x_8x_MciGetDataXferEndState() != 0);
- errorState = Lpc177x_8x_MciGetXferErrState();
- if ((num > 1) || errorState)
- {
- Lpc177x_8x_MciCmd_StopTransmission();
- }
- if (errorState)
- {
- #ifdef NUTDEBUG
- printf("%s() failed\n", __FUNCTION__ );
- Lpc177x_8x_MmcardShowStatusBits(errorState);
- #endif
- retVal = MCI_FUNC_FAILED;
- }
- }
- /* Release mutex access. */
- NutEventPost(&mutex);
- return(retVal);
- }
- /*!
- * \brief Initialize the multimedia card.
- *
- *
- * \param ifc Specifies the hardware interface.
- *
- * \return 0 on success, -1 otherwise.
- */
- static int Lpc177x_8x_MmcardInit(NUTDEVICE * dev)
- {
- int32_t retVal;
- en_Mci_CardType cardType;
- uint32_t rcAddress;
- MCIFC *ifc = (MCIFC *) dev->dev_icb;
- /* set default for addressing mode */
- ifc->ifc_admode = MMC_BLOCK_MODE;
- /* reset card data */
- memset(ifc->ifc_csd, 0, sizeof(ifc->ifc_csd));
- memset(&cidval, 0, sizeof(st_Mci_CardId));
- /*********************************/
- /* Init */
- /*********************************/
- retVal = Lpc177x_8x_MciInit(BRD_MCI_POWERED_ACTIVE_LEVEL);
- if (retVal != MCI_FUNC_OK)
- {
- #ifdef NUTDEBUG
- printf("%s() MciInit failed\n", __FUNCTION__ );
- #endif
- return((int)retVal);
- }
- /*********************************/
- /* CardType */
- /*********************************/
- cardType = Lpc177x_8x_MciGetCardType();
- if (cardType == MCI_CARD_UNKNOWN)
- {
- #ifdef NUTDEBUG
- printf("%s() Get Card Type\n", __FUNCTION__ );
- #endif
- return(MCI_FUNC_FAILED);
- }
- else
- {
- // the cardtype will tell us if BLOCK or BYTE addressing whould be used
- if (cardType == MCI_SDHC_SDXC_CARD)
- {
- ifc->ifc_admode = MMC_BYTE_MODE;
- }
- }
- /*********************************/
- /* CID */
- /*********************************/
- retVal = Lpc177x_8x_MciGetCID(&cidval);
- if (retVal != MCI_FUNC_OK)
- {
- #ifdef NUTDEBUG
- printf("%s() Get CID failed\n", __FUNCTION__ );
- #endif
- return((int)retVal);
- }
- /*********************************/
- /* Card Address */
- /*********************************/
- retVal = Lpc177x_8x_MciSetCardAddress();
- if (retVal != MCI_FUNC_OK)
- {
- #ifdef NUTDEBUG
- printf("%s() Set card address failed\n", __FUNCTION__ );
- #endif
- return((int)retVal);
- }
- else
- {
- rcAddress = Lpc177x_8x_MciGetCardAddress();
- ifc->ifc_reladdr = rcAddress;
- }
- /*********************************/
- /* CSD */
- /*********************************/
- retVal = Lpc177x_8x_MciGetCSD(ifc->ifc_csd);
- if (retVal != MCI_FUNC_OK)
- {
- #ifdef NUTDEBUG
- printf("%s() GetCSD failed\n", __FUNCTION__ );
- #endif
- return((int)retVal);
- }
- /*********************************/
- /* Card Select */
- /*********************************/
- retVal = Lpc177x_8x_MciCmd_SelectCard();
- if (retVal != MCI_FUNC_OK)
- {
- #ifdef NUTDEBUG
- printf("%s() Card select CMD failed\n", __FUNCTION__ );
- #endif
- return((int)retVal);
- }
- /*********************************/
- /* Bandwidth */
- /*********************************/
- if (cardType == MCI_SDSC_V1_CARD || cardType == MCI_SDSC_V2_CARD || cardType == MCI_SDHC_SDXC_CARD)
- {
- Lpc177x_8x_MciSetClock( MCI_NORMAL_RATE );
- if (Lpc177x_8x_MciSetBusWidth( SD_4_BIT ) != MCI_FUNC_OK)
- {
- return((int)retVal);
- }
- }
- /*********************************/
- /* BlockLength */
- /*********************************/
- retVal = Lpc177x_8x_MciSetBlockLen(BLOCK_LENGTH);
- if (retVal != MCI_FUNC_OK)
- {
- return((int)retVal);
- }
- return(MCI_FUNC_OK);
- }
- /*!
- * \brief Read data blocks from a mounted partition.
- *
- * Applications should not call this function directly, but use the
- * stdio interface.
- *
- * \param nfp Pointer to a ::NUTFILE structure, obtained by a previous
- * call to MmCardMount().
- * \param buffer Pointer to the data buffer to fill.
- * \param num Maximum number of blocks to read. However, reading
- * multiple blocks is not yet supported by this driver.
- *
- * \return The number of blocks actually read. A return value of -1
- * indicates an error.
- */
- static int Lpc177x_8x_MmcardBlockRead(NUTFILE * nfp, void *buffer, int num)
- {
- MMCFCB *fcb = (MMCFCB *) nfp->nf_fcb;
- uint32_t blk = fcb->fcb_blknum;
- NUTDEVICE *dev = (NUTDEVICE *) nfp->nf_dev;
- MCIFC *ifc = (MCIFC *) dev->dev_icb;
- if (buffer == 0)
- {
- buffer = fcb->fcb_blkbuf;
- }
- /*
- * when using the filesystem, the sectornumbering is different then when
- * directly accesing the card. For example, the MBR can be found at the
- * sector 0 of the card, but the filesystem's first sector is the sector
- * where the start is of the FAT VolumeID (also called the BOOT SECTOR).
- * This position (or offset) is indicated by reading the partion-table,
- * more specific: by reading the LBA begin info.
- * This offset we need to add here to the sector# we get in as
- * parameter. This way we acces the real sector on the card.
- *
- */
- if ((ifc->ifc_config & MBR_P_TABLE_NOT_PRESENT) == 0)
- {
- // only add offset if a partition table was present, else, don't add anything
- blk += fcb->fcb_part.part_sect_offs;
- }
- if (ifc->ifc_admode == MMC_BLOCK_MODE)
- {
- // apply addressing mode here
- blk *= BLOCK_LENGTH;
- }
- if (Lpc177x_8x_MmcardReadData(fcb->fcb_blkbuf, blk, 1) == MCI_FUNC_OK)
- {
- // return the number of blocks that were succesfully read
- return(num);
- }
- #ifdef NUTDEBUG
- printf("%s() failed\n", __FUNCTION__ );
- #endif
- return(-1);
- }
- /*!
- * \brief Write data blocks to a mounted partition.
- *
- * Applications should not call this function directly, but use the
- * stdio interface.
- *
- * \param nfp Pointer to a \ref NUTFILE structure, obtained by a previous
- * call to MmCardMount().
- * \param buffer Pointer to the data to be written.
- * \param num Maximum number of blocks to write. However, writing
- * multiple blocks is not yet supported by this driver.
- *
- * \return The number of blocks written. A return value of -1 indicates an
- * error.
- */
- static int Lpc177x_8x_MmcardBlockWrite(NUTFILE * nfp, const void *buffer, int num)
- {
- MMCFCB *fcb = (MMCFCB *) nfp->nf_fcb;
- uint32_t blk = fcb->fcb_blknum;
- NUTDEVICE *dev = (NUTDEVICE *) nfp->nf_dev;
- MCIFC *ifc = (MCIFC *) dev->dev_icb;
- if (buffer == 0)
- {
- buffer = fcb->fcb_blkbuf;
- }
- /*
- * when using the filesystem, the sectornumbering is different then when
- * directly accesing the card. For example, the MBR can be found at the
- * sector 0 of the card, but the filesystem's first sector is the sector
- * where the start is of the FAT VolumeID (also called the BOOT SECTOR).
- * This position (or offset) is indicated by reading the partion-table,
- * more specific: by reading the LBA begin info.
- * This offset we need to add here to the sector# we get in as
- * parameter. This way we acces the real sector on the card.
- *
- */
- if ((ifc->ifc_config & MBR_P_TABLE_NOT_PRESENT) == 0)
- {
- // only add offset if a partition table was present, else, don't add anything
- blk += fcb->fcb_part.part_sect_offs;
- }
- if (ifc->ifc_admode == MMC_BLOCK_MODE)
- {
- // apply addressing mode here
- blk *= BLOCK_LENGTH;
- }
- if (Lpc177x_8x_MmcardWriteData((uint8_t*)buffer, blk, num) == MCI_FUNC_OK)
- {
- return(num);
- }
- #ifdef NUTDEBUG
- printf("%s() failed\n", __FUNCTION__ );
- #endif
- return(-1);
- }
- /*!
- * \brief Mount a partition.
- *
- * Nut/OS doesn't provide specific routines for mounting. Instead routines
- * for opening files are used.
- *
- * Applications should not directly call this function, but use the high
- * level stdio routines for opening a file.
- *
- * \param dev Pointer to the MMC device.
- * \param name Partition number followed by a slash followed by a name
- * of the file system device. Both items are optional. If no
- * file system driver name is given, the first file system
- * driver found in the list of registered devices will be
- * used. If no partition number is specified or if partition
- * zero is given, the first active primary partition will be
- * used.
- * \param mode Opening mode. Currently ignored, but
- * \code _O_RDWR | _O_BINARY \endcode should be used for
- * compatibility with future enhancements.
- * \param acc File attributes, ignored.
- *
- * \return Pointer to a newly created file pointer to the mounted
- * partition or NUTFILE_EOF in case of any error.
- */
- static NUTFILE *Lpc177x_8x_MmcardMount(NUTDEVICE * dev, const char *name, int mode, int acc)
- {
- int partno = 0;
- u_int i;
- NUTDEVICE *fsdev;
- NUTFILE *nfp;
- MMCFCB *fcb;
- DOSPART *part;
- MCIFC *ifc = (MCIFC *) dev->dev_icb;
- FSCP_VOL_MOUNT mparm;
- /* Set the card in SDIO mode and check for SD-HC cards. */
- if (Lpc177x_8x_MmcardInit(dev))
- {
- errno = ENODEV;
- #ifdef NUTDEBUG
- printf("%s() Card init failed\n", __FUNCTION__ );
- #endif
- return(NUTFILE_EOF);
- }
- ifc->ifc_config = 0; // make sure a default is set before adding new info later on
- /* Parse the name for a partition number and a file system driver. */
- if (*name)
- {
- partno = atoi(name);
- do
- {
- name++;
- } while (*name && *name != '/');
- if (*name == '/')
- {
- name++;
- }
- }
- /*
- * Check the list of registered devices for the given name of the
- * files system driver. If none has been specified, get the first
- * file system driver in the list. Hopefully the application
- * registered one only.
- */
- for (fsdev = nutDeviceList; fsdev; fsdev = fsdev->dev_next)
- {
- if (*name == 0)
- {
- if (fsdev->dev_type == IFTYP_FS)
- {
- break;
- }
- }
- else if (strcmp(fsdev->dev_name, name) == 0)
- {
- break;
- }
- }
- if (fsdev == 0)
- {
- #ifdef NUTDEBUG
- printf("%s() FS driver not found\n", __FUNCTION__ );
- #endif
- errno = ENODEV;
- return(NUTFILE_EOF);
- }
- if ((fcb = NutHeapAllocClear(sizeof(MMCFCB))) == 0)
- {
- errno = ENOMEM;
- #ifdef NUTDEBUG
- printf("%s() Out of memory\n", __FUNCTION__ );
- #endif
- return(NUTFILE_EOF);
- }
- // link this block-device driver with the file system device driver
- fcb->fcb_fsdev = fsdev;
- // Initialize MMC access mutex semaphore. */
- NutEventPost(&mutex);
- /* Read MBR. */
- if (Lpc177x_8x_MmcardReadData(fcb->fcb_blkbuf, 0, 1) != MCI_FUNC_OK)
- {
- NutHeapFree(fcb);
- #ifdef NUTDEBUG
- printf("%s() Reading MBR failed\n", __FUNCTION__);
- #endif
- return(NUTFILE_EOF);
- }
- // check sanity of MBR
- if ((fcb->fcb_blkbuf[510]!=0x55) || (fcb->fcb_blkbuf[511]!=0xAA))
- {
- #ifdef NUTDEBUG
- printf("%s() Invalid MBR\n", __FUNCTION__ );
- #endif
- NutHeapFree(fcb);
- return(NUTFILE_EOF);
- }
- /* Read partition table. */
- part = (DOSPART *) & fcb->fcb_blkbuf[DOSPART_SECTORPOS];
- for (i = 1; i <= 4; i++)
- {
- if (partno)
- {
- if (i == partno)
- {
- /* Found specified partition number. */
- fcb->fcb_part = *part;
- break;
- }
- }
- else if (part->part_state & 0x80)
- {
- /* Located first active partition. */
- fcb->fcb_part = *part;
- break;
- }
- part++;
- }
- if (fcb->fcb_part.part_type == PTYPE_EMPTY)
- {
- #ifdef NUTDEBUG
- printf("%s() Invalid partition type\n", __FUNCTION__ );
- #endif
- NutHeapFree(fcb);
- return(NUTFILE_EOF);
- }
- #ifdef NUTDEBUG
- printf("Number of sectors %lu\n", fcb->fcb_part.part_sects);
- printf("Starting LBA %lu\n", fcb->fcb_part.part_sect_offs);
- #endif
- if ((nfp = NutHeapAllocClear(sizeof(NUTFILE))) == 0)
- {
- NutHeapFree(fcb);
- errno = ENOMEM;
- #ifdef NUTDEBUG
- printf("%s() Out of memory\n", __FUNCTION__ );
- #endif
- return(NUTFILE_EOF);
- }
- nfp->nf_dev = dev;
- nfp->nf_fcb = fcb;
- /*
- * Mount the file system volume.
- */
- mparm.fscp_bmnt = nfp;
- mparm.fscp_part_type = fcb->fcb_part.part_type;
- if (fsdev->dev_ioctl(fsdev, FS_VOL_MOUNT, &mparm))
- {
- #ifdef NUTDEBUG
- printf("%s() Mounting failed, try without partition table\n", __FUNCTION__ );
- #endif
- // try again, this time leaving out the partition table offset
- ifc->ifc_config |= MBR_P_TABLE_NOT_PRESENT;
- if (fsdev->dev_ioctl(fsdev, FS_VOL_MOUNT, &mparm))
- {
- // failed again...
- // destroy allocated nfp block (and UNMOUNT the FS (again))
- Lpc177x_8x_MmcardUnmount(nfp);
- #ifdef NUTDEBUG
- printf("%s() No FAT filesystem found, mounting failed\n", __FUNCTION__ );
- #endif
- NutHeapFree(fcb);
- return(NUTFILE_EOF);
- }
- }
- return(nfp);
- }
- /*!
- * \brief Unmount a previously mounted partition.
- *
- * Applications should not directly call this function, but use the high
- * level stdio routines for closing a previously opened file.
- *
- * \return 0 on success, -1 otherwise.
- */
- static int Lpc177x_8x_MmcardUnmount(NUTFILE * nfp)
- {
- int rc = -1;
- if (nfp)
- {
- MMCFCB *fcb = (MMCFCB *) nfp->nf_fcb;
- if (fcb)
- {
- rc = fcb->fcb_fsdev->dev_ioctl(fcb->fcb_fsdev, FS_VOL_UNMOUNT, NULL);
- NutHeapFree(fcb);
- }
- NutHeapFree(nfp);
- }
- #ifdef NUTDEBUG
- if (rc != 0)
- {
- printf("%s() failed\n", __FUNCTION__ );
- }
- #endif
- return(rc);
- }
- /*!
- * \brief Perform MMC control functions.
- *
- * This function is called by the ioctl() function of the C runtime
- * library. Applications should not directly call this function.
- *
- * \todo Card change detection should verify the serial card number.
- *
- * \param dev Identifies the device that receives the device-control
- * function.
- * \param req Requested control function. May be set to one of the
- * following constants:
- * - \ref NUTBLKDEV_MEDIACHANGE
- * - \ref NUTBLKDEV_INFO
- * - \ref NUTBLKDEV_SEEK
- * - \ref MMCARD_GETCID
- * - \ref MMCARD_GETCSD
- *
- * \param conf Points to a buffer that contains any data required for
- * the given control function or receives data from that
- * function.
- * \return 0 on success, -1 otherwise.
- */
- static int Lpc177x_8x_MmcardIOCtl(NUTDEVICE * dev, int req, void *conf)
- {
- int rc = 0;
- switch (req)
- {
- case NUTBLKDEV_MEDIAAVAIL:
- {
- *((int *) conf) = 1;
- }
- break;
- case NUTBLKDEV_MEDIACHANGE:
- {
- *((int *) conf) = 0;
- }
- break;
- case NUTBLKDEV_INFO:
- {
- BLKPAR_INFO *par = (BLKPAR_INFO *) conf;
- MMCFCB *fcb = (MMCFCB *) par->par_nfp->nf_fcb;
- /*
- * note that we don't read the card's CSD-register for this info,
- * in stead, we use the info that we found in the partition table of
- * the formatted card.
- */
- //
- par->par_nblks = fcb->fcb_part.part_sects;
- par->par_blksz = MMC_BLOCK_SIZE;
- par->par_blkbp = fcb->fcb_blkbuf;
- }
- break;
- case NUTBLKDEV_SEEK:
- {
- BLKPAR_SEEK *par = (BLKPAR_SEEK *) conf;
- MMCFCB *fcb = (MMCFCB *) par->par_nfp->nf_fcb;
- fcb->fcb_blknum = par->par_blknum;
- }
- break;
- case MMCARD_GETSTATUS:
- rc = Lpc177x_8x_MciGetCardStatus((int32_t*) conf);
- break;
- case MMCARD_GETCID:
- // not possible to issue a single CID command here so return the
- // captured value from init
- memcpy((st_Mci_CardId*)conf, &cidval, sizeof(st_Mci_CardId));
- break;
- case MMCARD_GETCSD:
- // not possible to issue a single CSD command here so return the
- // captured value from init
- memcpy((st_Mci_CardId*)conf, &mci0_ifc.ifc_csd, sizeof(mci0_ifc.ifc_csd));
- break;
- default:
- rc = -1;
- break;
- }
- return(rc);
- }
- /*!
- * \brief Multimedia card device information structure.
- *
- * A pointer to this structure must be passed to NutRegisterDevice()
- * to bind this driver to the Nut/OS kernel. An application may then
- * call
- * /verbatim
- * _open("MMC0:", _O_RDWR | _O_BINARY);
- * /endverbatim
- * to mount the first active primary partition with any previously
- * registered file system driver (typically devPhat0).
- */
- NUTDEVICE devLpcMci0 = {
- 0, /*!< Pointer to next device, dev_next. */
- {'M', 'M', 'C', '0', 0, 0, 0, 0, 0}
- , /*!< Unique device name, dev_name. */
- 0, /*!< Type of device, dev_type. Obsolete. */
- 0, /*!< Base address, dev_base. Unused. */
- 0, /*!< First interrupt number, dev_irq. Unused. */
- &mci0_ifc, /*!< Interface control block, dev_icb. */
- 0, /*!< Driver control block used by the low level part, dev_dcb. */
- Lpc177x_8x_MmcardInit, /*!< Driver initialization routine, dev_init. */
- Lpc177x_8x_MmcardIOCtl, /*!< Driver specific control function, dev_ioctl. */
- Lpc177x_8x_MmcardBlockRead, /*!< Read data from a file, dev_read. */
- Lpc177x_8x_MmcardBlockWrite,/*!< Write data to a file, dev_write. */
- Lpc177x_8x_MmcardMount, /*!< Mount a file system, dev_open. */
- Lpc177x_8x_MmcardUnmount, /*!< Unmount a file system, dev_close. */
- 0, /*!< Return file size, dev_size. */
- 0, /*!< Select function, optional, not yet implemented */
- };
- /*@}*/
|