| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484 |
- /*
- * Copyright (C) 2008-2009 by egnite GmbH
- * Copyright (C) 2006 by egnite Software 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/
- */
- /*!
- * \file dev/blockdev.c
- * \brief Generic block I/O device routines.
- *
- * \verbatim
- * $Id: blockdev.c 5472 2013-12-06 00:16:28Z olereinhardt $
- * \endverbatim
- */
- #include <cfg/os.h>
- #include <cfg/memory.h>
- #include <dev/blockdev.h>
- #include <sys/nutdebug.h>
- #include <fs/fs.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <memdebug.h>
- /*!
- * \brief Block volume information structure type.
- */
- typedef struct _BLOCKVOLUME BLOCKVOLUME;
- /*!
- * \brief Block volume information structure.
- */
- struct _BLOCKVOLUME {
- /*! \brief Attached file system device.
- */
- NUTDEVICE *vol_fsdev;
- /*! \brief Number of blocks available to the file system.
- */
- uint32_t vol_blk_cnt;
- /*! \brief Number of bytes in a block.
- */
- int vol_blk_len;
- /*! \brief First page used by the file system.
- */
- uint32_t vol_blk_off;
- /*! \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 zero based.
- */
- uint32_t vol_blk_num;
- /*! \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.
- */
- uint8_t *vol_blk_buf;
- };
- /*!
- * \brief Initialize the block I/O device.
- *
- * This dummy routine may be used by drivers, which do not need any
- * specific initialization.
- *
- * \param dev Specifies the device.
- *
- * \return Always 0.
- */
- int NutBlockDeviceInit(NUTDEVICE * dev)
- {
- NUTASSERT(dev != NULL);
- return 0;
- }
- /*!
- * \brief Mount a volume.
- *
- * 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 Specifies the block I/O 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.
- */
- NUTFILE *NutBlockDeviceOpen(NUTDEVICE * dev, const char *name, int mode, int acc)
- {
- NUTDEVICE *fsdev;
- /* Parse name for a file system driver, skip partition number. */
- NUTASSERT(name != NULL);
- if (*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.
- */
- if (*name) {
- fsdev = NutDeviceLookup(name);
- } else {
- fsdev = NutDeviceLookupType(NULL, IFTYP_FS);
- }
- if (fsdev == NULL) {
- errno = ENODEV;
- } else {
- BLOCKVOLUME *fcb = malloc(sizeof(BLOCKVOLUME));
- if (fcb) {
- NUTBLOCKIO *blkio;
- NUTASSERT(dev != NULL);
- blkio = (NUTBLOCKIO *) (dev->dev_dcb);
- NUTASSERT(blkio != NULL);
- fcb->vol_fsdev = fsdev;
- fcb->vol_blk_off = blkio->blkio_vol_bot;
- fcb->vol_blk_cnt = blkio->blkio_blk_cnt - blkio->blkio_vol_bot - blkio->blkio_vol_top;
- fcb->vol_blk_num = 0;
- fcb->vol_blk_len = blkio->blkio_blk_siz;
- fcb->vol_blk_buf = malloc(fcb->vol_blk_len);
- if (fcb->vol_blk_buf) {
- NUTFILE *nfp = malloc(sizeof(NUTFILE));
- if (nfp) {
- FSCP_VOL_MOUNT mparm;
- nfp->nf_dev = dev;
- nfp->nf_fcb = fcb;
- /* Mount the file system volume. */
- mparm.fscp_bmnt = nfp;
- mparm.fscp_part_type = 0;
- if (fsdev->dev_ioctl(fsdev, FS_VOL_MOUNT, &mparm) == 0) {
- /* Successful return. */
- return nfp;
- }
- free(nfp);
- }
- }
- free(fcb);
- }
- }
- return NUTFILE_EOF;
- }
- /*!
- * \brief Unmount a currently mounted volume.
- *
- * \param nfp File pointer to a previously mounted volume.
- *
- * \return 0 on success, -1 otherwise.
- */
- int NutBlockDeviceClose(NUTFILE * nfp)
- {
- int rc = -1;
- BLOCKVOLUME *fcb;
- NUTASSERT(nfp != NULL);
- fcb = (BLOCKVOLUME *) nfp->nf_fcb;
- if (fcb) {
- NUTASSERT(fcb->vol_fsdev != NULL);
- NUTASSERT(fcb->vol_fsdev->dev_ioctl != NULL);
- rc = fcb->vol_fsdev->dev_ioctl(fcb->vol_fsdev, FS_VOL_UNMOUNT, NULL);
- free(fcb);
- }
- free(nfp);
- return rc;
- }
- /*!
- * \brief Perform block I/O device control functions.
- *
- * This function is called by the ioctl() function of the C runtime
- * library. Applications should not directly call this function.
- *
- * Unkown requests are passed to the block I/O device.
- *
- * \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_INFO, conf points to a \ref BLKPAR_INFO structure.
- * - \ref NUTBLKDEV_SEEK, conf points to a \ref BLKPAR_SEEK structure.
- *
- * \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.
- */
- int NutBlockDeviceIOCtl(NUTDEVICE * dev, int req, void *conf)
- {
- int rc = 0;
- switch (req) {
- case NUTBLKDEV_SEEK:
- {
- BLKPAR_SEEK *par = (BLKPAR_SEEK *) conf;
- BLOCKVOLUME *fcb;
- /* Sanity check. */
- NUTASSERT(conf != NULL);
- NUTASSERT(par->par_nfp != NULL);
- NUTASSERT(par->par_nfp->nf_fcb != NULL);
- fcb = (BLOCKVOLUME *) par->par_nfp->nf_fcb;
- fcb->vol_blk_num = par->par_blknum;
- }
- break;
- case NUTBLKDEV_INFO:
- {
- BLKPAR_INFO *par;
- BLOCKVOLUME *fcb;
- NUTASSERT(conf != NULL);
- par = (BLKPAR_INFO *) conf;
- NUTASSERT(par->par_nfp != NULL);
- NUTASSERT(par->par_nfp->nf_fcb != NULL);
- fcb = (BLOCKVOLUME *) par->par_nfp->nf_fcb;
- par->par_nblks = fcb->vol_blk_cnt;
- par->par_blksz = fcb->vol_blk_len;
- par->par_blkbp = fcb->vol_blk_buf;
- }
- break;
- default:
- {
- NUTBLOCKIO *blkio;
- NUTASSERT(dev != NULL);
- NUTASSERT(dev->dev_dcb != NULL);
- blkio = (NUTBLOCKIO *) (dev->dev_dcb);
- NUTASSERT(blkio->blkio_ioctl != NULL);
- rc = blkio->blkio_ioctl(dev, req, conf);
- }
- break;
- }
- return rc;
- }
- /*!
- * \brief Read data blocks from a mounted volume.
- *
- * The current position may have been set by a previous I/O control
- * \ref NUTBLKDEV_SEEK.
- *
- * Applications should not call this function directly, but use the
- * stdio interface.
- *
- * \param nfp File pointer to a previously mounted volume.
- * \param buffer Pointer to the data buffer to fill.
- * \param num Number of blocks to read.
- *
- * \return The number of blocks actually read. The current position is
- * set to the next unread block. A return value of -1 indicates
- * an error.
- */
- int NutBlockDeviceRead(NUTFILE * nfp, void *buffer, int num)
- {
- int rc;
- int cnt;
- uint8_t *bp = buffer;
- NUTBLOCKIO *blkio;
- BLOCKVOLUME *fcb;
- /* Sanity checks. */
- if (num == 0) {
- return 0;
- }
- NUTASSERT(buffer != NULL);
- NUTASSERT(nfp != NULL);
- NUTASSERT(nfp->nf_fcb != NULL);
- NUTASSERT(nfp->nf_dev != NULL);
- NUTASSERT(nfp->nf_dev->dev_dcb != NULL);
- blkio = nfp->nf_dev->dev_dcb;
- fcb = (BLOCKVOLUME *) nfp->nf_fcb;
- NUTASSERT(blkio->blkio_read != NULL);
- for (rc = 0; rc < num; rc++) {
- if (fcb->vol_blk_num >= fcb->vol_blk_cnt) {
- break;
- }
- cnt = (*blkio->blkio_read) (nfp->nf_dev, fcb->vol_blk_num + fcb->vol_blk_off, bp, fcb->vol_blk_len);
- if (cnt != fcb->vol_blk_len) {
- break;
- }
- fcb->vol_blk_num++;
- bp += fcb->vol_blk_len;
- }
- return rc ? rc : -1;
- }
- /*!
- * \brief Write data blocks to a mounted volume.
- *
- * The current position may have been set by a previous I/O control
- * \ref NUTBLKDEV_SEEK.
- *
- * Applications should not call this function directly, but use the
- * stdio interface.
- *
- * \param nfp File pointer to a previously mounted volume.
- * \param buffer Pointer to the data to be written.
- * \param num Number of blocks to write.
- *
- * \return The number of blocks actually written. The current position is
- * set to the next block. A return value of -1 indicates an error.
- */
- int NutBlockDeviceWrite(NUTFILE * nfp, const void *buffer, int num)
- {
- int rc;
- int cnt;
- const uint8_t *bp = buffer;
- NUTBLOCKIO *blkio;
- BLOCKVOLUME *fcb;
- /* Sanity checks. */
- if (num == 0) {
- return 0;
- }
- NUTASSERT(nfp != NULL);
- NUTASSERT(nfp->nf_fcb != NULL);
- NUTASSERT(nfp->nf_dev != NULL);
- NUTASSERT(nfp->nf_dev->dev_dcb != NULL);
- fcb = (BLOCKVOLUME *) nfp->nf_fcb;
- blkio = nfp->nf_dev->dev_dcb;
- NUTASSERT(blkio->blkio_write != NULL);
- for (rc = 0; rc < num; rc++) {
- if (fcb->vol_blk_num >= fcb->vol_blk_cnt) {
- break;
- }
- cnt = (*blkio->blkio_write) (nfp->nf_dev, fcb->vol_blk_num + fcb->vol_blk_off, bp, fcb->vol_blk_len);
- if (cnt != fcb->vol_blk_len) {
- break;
- }
- fcb->vol_blk_num++;
- bp += fcb->vol_blk_len;
- }
- return rc ? rc : -1;
- }
- #ifdef __HARVARD_ARCH__
- /*!
- * \brief Write data blocks from program space to a mounted volume.
- *
- * Similar to NutBlockDeviceWrite() except that the data is located in
- * program memory.
- *
- * Applications should not call this function directly, but use the
- * stdio interface.
- *
- * \param nfp File pointer to a previously mounted volume.
- * \param buffer Pointer to the data bytes in program space to be written.
- * \param num Number of blocks to write.
- *
- * \return The number of blocks actually written. The current position is
- * set to the next block. A return value of -1 indicates an error.
- */
- int NutBlockDeviceWrite_P(NUTFILE * nfp, PGM_P buffer, int num)
- {
- int rc = 0;
- int cnt;
- PGM_P bp = buffer;
- NUTBLOCKIO *blkio;
- BLOCKVOLUME *fcb;
- /* Sanity checks. */
- if (num == 0) {
- return 0;
- }
- NUTASSERT(nfp != NULL);
- NUTASSERT(nfp->nf_fcb != NULL);
- NUTASSERT(nfp->nf_dev != NULL);
- NUTASSERT(nfp->nf_dev->dev_dcb != NULL);
- fcb = (BLOCKVOLUME *) nfp->nf_fcb;
- blkio = nfp->nf_dev->dev_dcb;
- NUTASSERT(blkio->blkio_write != NULL);
- for (rc = 0; rc < num; rc++) {
- if (fcb->vol_blk_num >= fcb->vol_blk_cnt) {
- break;
- }
- cnt = (*blkio->blkio_write_P) (nfp->nf_dev, fcb->vol_blk_num + fcb->vol_blk_off, bp, fcb->vol_blk_len);
- if (cnt != fcb->vol_blk_len) {
- break;
- }
- fcb->vol_blk_num++;
- bp += fcb->vol_blk_len;
- }
- return rc ? rc : -1;
- }
- #endif
- /*!
- * \brief Return the size of a mounted volume.
- *
- * \param nfp File pointer to a previously mounted volume.
- *
- * \return Total number of bytes.
- */
- long NutBlockDeviceSize(NUTFILE * nfp)
- {
- BLOCKVOLUME *fcb;
- NUTASSERT(nfp != NULL);
- fcb = (BLOCKVOLUME *) nfp->nf_fcb;
- NUTASSERT(fcb != NULL);
- return (long) fcb->vol_blk_cnt * (long) fcb->vol_blk_len;
- }
|