Nut/OS  4.10.3
API Reference
rawfs.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008-2009 by egnite GmbH
00003  * Copyright (C) 2005-2006 by egnite Software 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 THE COPYRIGHT HOLDERS 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 THE
00024  * COPYRIGHT OWNER 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 
00049 #include <dev/blockdev.h>
00050 #include <sys/event.h>
00051 #include <sys/nutdebug.h>
00052 
00053 #include <fs/fs.h>
00054 
00055 #include <stdlib.h>
00056 #include <string.h>
00057 #include <errno.h>
00058 #include <memdebug.h>
00059 
00060 #include <fs/rawfs.h>
00061 
00062 #if 0
00063 /* Use for local debugging. */
00064 #define NUTDEBUG
00065 #include <stdio.h>
00066 #endif
00067 
00068 #ifndef SEEK_SET
00069 #  define SEEK_SET        0     /* Seek from beginning of file.  */
00070 #  define SEEK_CUR        1     /* Seek from current position.  */
00071 #  define SEEK_END        2     /* Set file pointer to EOF plus "offset" */
00072 #endif
00073 
00078 
00088 static int RawFsSectorFlush(NUTDEVICE * dev)
00089 {
00090     int rc = 0;
00091     RAWVOLUME *vol = (RAWVOLUME *) dev->dev_dcb;
00092 
00093     /* Write dirty sectors only. */
00094     if (vol->vol_sect_dirty) {
00095         BLKPAR_SEEK pars;
00096         NUTFILE *blkmnt = dev->dev_icb;
00097         NUTDEVICE *blkdev = blkmnt->nf_dev;
00098 
00099         /* Set the block device's sector position. */
00100         pars.par_nfp = blkmnt;
00101         pars.par_blknum = vol->vol_sect_num;
00102         rc = (*blkdev->dev_ioctl) (blkdev, NUTBLKDEV_SEEK, &pars);
00103         if (rc == 0) {
00104             /* Write single block to the device. */
00105             if ((*blkdev->dev_write) (blkmnt, vol->vol_sect_buf, 1) == 1) {
00106                 /* Success, buffer is clean. */
00107                 vol->vol_sect_dirty = 0;
00108             } else {
00109                 rc = -1;
00110             }
00111         }
00112     }
00113     return rc;
00114 }
00115 
00124 static int RawFsSectorLoad(NUTDEVICE * dev, uint32_t sect)
00125 {
00126     int rc = -1;
00127     RAWVOLUME *vol;
00128 
00129     NUTASSERT(dev != NULL);
00130     vol = (RAWVOLUME *) dev->dev_dcb;
00131 
00132     /* Gain mutex access. */
00133     NUTASSERT(vol != NULL);
00134     NutEventWait(&vol->vol_iomutex, 0);
00135 
00136     /* Nothing to do if sector is already loaded. */
00137     if (vol->vol_sect_num == sect) {
00138         rc = 0;
00139     }
00140     /* Make sure that the sector buffer is clean. */
00141     else if (RawFsSectorFlush(dev) == 0) {
00142         NUTFILE *blkmnt = dev->dev_icb;
00143         NUTDEVICE *blkdev = blkmnt->nf_dev;
00144         BLKPAR_SEEK pars;
00145 
00146         blkmnt = dev->dev_icb;
00147         NUTASSERT(blkmnt != NULL);
00148         blkdev = blkmnt->nf_dev;
00149         NUTASSERT(blkdev != NULL);
00150 
00151         /* Set the block device's sector position. */
00152         pars.par_nfp = blkmnt;
00153         pars.par_blknum = sect;
00154         if ((*blkdev->dev_ioctl) (blkdev, NUTBLKDEV_SEEK, &pars) == 0) {
00155             /* Read a single block from the device. */
00156             if ((*blkdev->dev_read) (blkmnt, vol->vol_sect_buf, 1) == 1) {
00157                 vol->vol_sect_num = sect;
00158                 rc = 0;
00159             }
00160         }
00161     }
00162 
00163     /* Release mutex access. */
00164     NutEventPostAsync(&vol->vol_iomutex);
00165 
00166     return rc;
00167 }
00168 
00176 static int RawFsFileFlush(NUTFILE * nfp)
00177 {
00178     int rc;
00179     NUTDEVICE *dev;
00180     RAWVOLUME *vol;
00181 
00182     NUTASSERT(nfp != NULL);
00183     dev = nfp->nf_dev;
00184     NUTASSERT(dev != NULL);
00185     vol = (RAWVOLUME *) dev->dev_dcb;
00186     NUTASSERT(vol != NULL);
00187 
00188     /* Gain mutex access. */
00189     NutEventWait(&vol->vol_iomutex, 0);
00190     /* Flush sector buffer. */
00191     rc = RawFsSectorFlush(nfp->nf_dev);
00192     /* Release mutex access. */
00193     NutEventPost(&vol->vol_iomutex);
00194 
00195     return rc;
00196 }
00197 
00214 NUTFILE *RawFsFileOpen(NUTDEVICE * dev, CONST char *path, int mode, int acc)
00215 {
00216     NUTFILE *nfp;
00217     RAWFILE *fcb;
00218 
00219     /* Allocate a private file control block. */
00220     fcb = malloc(sizeof(RAWFILE));
00221     if (fcb) {
00222         memset(fcb, 0, sizeof(RAWFILE));
00223         fcb->f_mode = mode;
00224         /* Allocate a file information structure. */
00225         nfp = malloc(sizeof(NUTFILE));
00226         if (nfp) {
00227             nfp->nf_next = 0;
00228             nfp->nf_dev = dev;
00229             nfp->nf_fcb = fcb;
00230             /* Successfully opened. */
00231             return nfp;
00232         }
00233         free(fcb);
00234     }
00235     /* Return failure. */
00236     return NUTFILE_EOF;
00237 }
00238 
00247 int RawFsFileClose(NUTFILE * nfp)
00248 {
00249     int rc;
00250 
00251     NUTASSERT(nfp != NULL);
00252 
00253     rc = RawFsFileFlush(nfp);
00254     if (nfp->nf_fcb) {
00255         free(nfp->nf_fcb);
00256     }
00257     free(nfp);
00258 
00259     return rc;
00260 }
00261 
00274 int RawFsFileWrite(NUTFILE * nfp, CONST void *buffer, int len)
00275 {
00276     int rc;
00277     int step;
00278     uint8_t *buf;
00279     RAWFILE *fcb;
00280     RAWVOLUME *vol;
00281 
00282     NUTASSERT(nfp != NULL);
00283 
00284     /* Flush file if buffer is a NULL pointer. */
00285     if (buffer == NULL || len == 0) {
00286         return RawFsFileFlush(nfp);
00287     }
00288 
00289     /* Sanity check. */
00290     NUTASSERT(nfp->nf_fcb != NULL);
00291     NUTASSERT(nfp->nf_dev != NULL);
00292     NUTASSERT(nfp->nf_dev->dev_dcb != NULL);
00293 
00294     fcb = (RAWFILE *) nfp->nf_fcb;
00295     vol = (RAWVOLUME *) nfp->nf_dev->dev_dcb;
00296 
00297     /*
00298      * Write the data.
00299      */
00300     buf = (uint8_t *) buffer;
00301     for (rc = 0, step = 0; rc < len; rc += step) {
00302         /* Did we reach the end of a sector? */
00303         if (fcb->f_sect_pos >= vol->vol_sect_len) {
00304             /* Yes, move to the next sector. */
00305             fcb->f_sect_num++;
00306             fcb->f_sect_pos -= vol->vol_sect_len;
00307         }
00308         /* Load the sector we want to write to. */
00309         if (RawFsSectorLoad(nfp->nf_dev, fcb->f_sect_num)) {
00310             rc = -1;
00311             break;
00312         }
00313         /* The number of bytes we write to this sector. */
00314         step = (int) (vol->vol_sect_len - fcb->f_sect_pos);
00315         if (step > len - rc) {
00316             step = len - rc;
00317         }
00318         /* Copy data to this sector. */
00319         memcpy(&vol->vol_sect_buf[fcb->f_sect_pos], &buf[rc], step);
00320         vol->vol_sect_dirty = 1;
00321         /* Advance file pointers. */
00322         fcb->f_pos += step;
00323         fcb->f_sect_pos += step;
00324     }
00325     return rc;
00326 }
00327 
00328 #ifdef __HARVARD_ARCH__
00329 
00346 int RawFsFileWrite_P(NUTFILE * nfp, PGM_P buffer, int len)
00347 {
00348     return -1;
00349 }
00350 #endif
00351 
00363 int RawFsFileRead(NUTFILE * nfp, void *buffer, int size)
00364 {
00365     int rc;
00366     int step;
00367     uint8_t *buf;
00368     RAWVOLUME *vol;
00369     RAWFILE *fcb;
00370 
00371     /* Ignore input flush. */
00372     if (buffer == NULL || size == 0) {
00373         return 0;
00374     }
00375 
00376     NUTASSERT(nfp != NULL);
00377     NUTASSERT(nfp->nf_dev != NULL);
00378     fcb = nfp->nf_fcb;
00379     NUTASSERT(fcb != NULL);
00380     vol = (RAWVOLUME *) nfp->nf_dev->dev_dcb;
00381     NUTASSERT(vol != NULL);
00382 
00383     buf = (uint8_t *) buffer;
00384     for (rc = 0, step = 0; rc < size; rc += step) {
00385         /* Did we reach the end of a sector? */
00386         if (fcb->f_sect_pos >= vol->vol_sect_len) {
00387             /* Yes, move to the next sector. */
00388             fcb->f_sect_num++;
00389             fcb->f_sect_pos -= vol->vol_sect_len;
00390         }
00391         /* Make sure that the required sector is loaded. */
00392         if (RawFsSectorLoad(nfp->nf_dev, fcb->f_sect_num)) {
00393             rc = -1;
00394             break;
00395         }
00396         step = (int) (vol->vol_sect_len - fcb->f_sect_pos);
00397         if (step > size - rc) {
00398             step = size - rc;
00399         }
00400         memcpy(&buf[rc], &vol->vol_sect_buf[fcb->f_sect_pos], step);
00401         fcb->f_pos += step;
00402         fcb->f_sect_pos += step;
00403     }
00404     return rc;
00405 }
00406 
00418 static long RawFsFileSize(NUTFILE * nfp)
00419 {
00420     RAWVOLUME *vol;
00421 
00422     NUTASSERT(nfp != NULL);
00423     NUTASSERT(nfp->nf_dev != NULL);
00424     vol = (RAWVOLUME *) nfp->nf_dev->dev_dcb;
00425 
00426     return vol->vol_sect_cnt * vol->vol_sect_len;
00427 }
00428 
00441 static int RawFsFileSeek(NUTFILE * nfp, long *pos, int whence)
00442 {
00443     int rc = 0;
00444     long npos;
00445     RAWFILE *fcb;
00446 
00447     NUTASSERT(nfp != NULL);
00448     NUTASSERT(nfp->nf_fcb != NULL);
00449     fcb = nfp->nf_fcb;
00450 
00451     NUTASSERT(pos != NULL);
00452     npos = *pos;
00453 
00454     switch (whence) {
00455     case SEEK_CUR:
00456         /* Relative to current position. */
00457         npos += fcb->f_pos;
00458         break;
00459     case SEEK_END:
00460         /* Relative to file end. */
00461         npos += RawFsFileSize(nfp);
00462         break;
00463     }
00464 
00465     /* Make sure that we are within limits. */
00466     if (npos < 0 || npos > RawFsFileSize(nfp)) {
00467         errno = EINVAL;
00468         rc = -1;
00469     } else {
00470         RAWVOLUME *vol = (RAWVOLUME *) nfp->nf_dev->dev_dcb;
00471 
00472         NUTASSERT(nfp != NULL);
00473         NUTASSERT(nfp != NULL);
00474         vol = (RAWVOLUME *) nfp->nf_dev->dev_dcb;
00475 
00476         *pos = npos;
00477         fcb->f_pos = npos;
00478         fcb->f_sect_num = 0;
00479         while (npos >= (long)vol->vol_sect_len) {
00480             fcb->f_sect_num++;
00481             npos -= vol->vol_sect_len;
00482         }
00483         fcb->f_sect_pos = npos;
00484     }
00485     return rc;
00486 }
00487 
00498 int RawFsUnmount(NUTDEVICE * dev)
00499 {
00500     RAWVOLUME *vol;
00501 
00502     NUTASSERT(dev != NULL);
00503     vol = (RAWVOLUME *) dev->dev_dcb;
00504 
00505     /* Flush sector buffer. */
00506     RawFsSectorFlush(dev);
00507     /* Release the volume information structure  */
00508     if (vol) {
00509         free(vol);
00510     }
00511     return 0;
00512 }
00513 
00529 int RawFsMount(NUTDEVICE * dev, NUTFILE * blkmnt, uint8_t part_type)
00530 {
00531     BLKPAR_INFO pari;
00532     RAWVOLUME *vol;
00533 
00534     NUTASSERT(blkmnt != NULL);
00535     NUTASSERT(blkmnt->nf_dev != NULL);
00536     NUTASSERT(dev != NULL);
00537 
00538     /* Allocate the volume information structure  */
00539     if ((dev->dev_dcb = malloc(sizeof(RAWVOLUME))) == 0) {
00540         return -1;
00541     }
00542     vol = (RAWVOLUME *) memset(dev->dev_dcb, 0, sizeof(RAWVOLUME));
00543 
00544     /*
00545      * Query information from the block device driver.
00546      */
00547     pari.par_nfp = blkmnt;
00548     if ((*blkmnt->nf_dev->dev_ioctl) (blkmnt->nf_dev, NUTBLKDEV_INFO, &pari)) {
00549         free(vol);
00550         errno = ENODEV;
00551         return -1;
00552     }
00553     vol->vol_sect_num = pari.par_nblks;
00554     vol->vol_sect_cnt = pari.par_nblks;
00555     vol->vol_sect_len = (size_t) pari.par_blksz;
00556     vol->vol_sect_buf = pari.par_blkbp;
00557 
00558     /* Initialize mutual exclusion semaphores. */
00559     NutEventPost(&vol->vol_fsmutex);
00560     NutEventPost(&vol->vol_iomutex);
00561 
00562     dev->dev_icb = blkmnt;
00563 
00564     return 0;
00565 }
00566 
00583 static int RawFsIOCtl(NUTDEVICE * dev, int req, void *conf)
00584 {
00585     int rc = -1;
00586 
00587     switch (req) {
00588     case FS_FILE_SEEK:
00589         NUTASSERT(conf != NULL);
00590         RawFsFileSeek((NUTFILE *) ((IOCTL_ARG3 *) conf)->arg1,  /* */
00591                       (long *) ((IOCTL_ARG3 *) conf)->arg2,     /* */
00592                       (int) ((IOCTL_ARG3 *) conf)->arg3);
00593         break;
00594     case FS_VOL_MOUNT:
00595         {
00596             /* Mount a volume. */
00597             FSCP_VOL_MOUNT *par = (FSCP_VOL_MOUNT *) conf;
00598 
00599             NUTASSERT(par != NULL);
00600             NUTASSERT(dev != NULL);
00601             rc = RawFsMount(dev, par->fscp_bmnt, par->fscp_part_type);
00602             if (rc) {
00603                 /* Release resources on failures. */
00604                 RawFsUnmount(dev);
00605             }
00606         }
00607         break;
00608     case FS_VOL_UNMOUNT:
00609         /* Unmount a volume. */
00610         NUTASSERT(dev != NULL);
00611         rc = RawFsUnmount(dev);
00612         break;
00613     }
00614     return rc;
00615 }
00616 
00626 static int RawFsInit(NUTDEVICE * dev)
00627 {
00628     /* Nothing to do. */
00629     return 0;
00630 }
00631 
00635 static NUTFILE *RawFsApiFileOpen(NUTDEVICE * dev, CONST char *path, int mode, int acc)
00636 {
00637     NUTFILE *rc;
00638     RAWVOLUME *vol;
00639 
00640     NUTASSERT(dev != NULL);
00641     vol = (RAWVOLUME *) dev->dev_dcb;
00642     NUTASSERT(vol != NULL);
00643 
00644     /* Lock filesystem access. */
00645     NutEventWait(&vol->vol_fsmutex, 0);
00646     /* Call worker routine. */
00647     rc = RawFsFileOpen(dev, path, mode, acc);
00648     /* Release filesystem lock. */
00649     NutEventPost(&vol->vol_fsmutex);
00650 
00651     return rc;
00652 }
00653 
00657 static int RawFsApiFileClose(NUTFILE * nfp)
00658 {
00659     int rc;
00660     RAWVOLUME *vol;
00661 
00662     NUTASSERT(nfp != NULL);
00663     NUTASSERT(nfp->nf_dev != NULL);
00664     vol = (RAWVOLUME *) nfp->nf_dev->dev_dcb;
00665     NUTASSERT(vol != NULL);
00666 
00667     /* Lock filesystem access. */
00668     NutEventWait(&vol->vol_fsmutex, 0);
00669     /* Call worker routine. */
00670     rc = RawFsFileClose(nfp);
00671     /* Release filesystem lock. */
00672     NutEventPost(&vol->vol_fsmutex);
00673 
00674     return rc;
00675 }
00676 
00680 static int RawFsApiFileWrite(NUTFILE * nfp, CONST void *buffer, int len)
00681 {
00682     int rc;
00683     RAWVOLUME *vol;
00684 
00685     NUTASSERT(nfp != NULL);
00686     NUTASSERT(nfp->nf_dev != NULL);
00687     vol = (RAWVOLUME *) nfp->nf_dev->dev_dcb;
00688     NUTASSERT(vol != NULL);
00689 
00690     /* Lock filesystem access. */
00691     NutEventWait(&vol->vol_fsmutex, 0);
00692     /* Call worker routine. */
00693     rc = RawFsFileWrite(nfp, buffer, len);
00694     /* Release filesystem lock. */
00695     NutEventPost(&vol->vol_fsmutex);
00696 
00697     return rc;
00698 }
00699 
00700 #ifdef __HARVARD_ARCH__
00701 
00704 static int RawFsApiFileWrite_P(NUTFILE * nfp, PGM_P buffer, int len)
00705 {
00706     int rc;
00707     RAWVOLUME *vol;
00708 
00709     NUTASSERT(nfp != NULL);
00710     NUTASSERT(nfp->nf_dev != NULL);
00711     vol = (RAWVOLUME *) nfp->nf_dev->dev_dcb;
00712     NUTASSERT(vol != NULL);
00713 
00714     /* Lock filesystem access. */
00715     NutEventWait(&vol->vol_fsmutex, 0);
00716     /* Call worker routine. */
00717     rc = RawFsFileWrite_P(nfp, buffer, len);
00718     /* Release filesystem lock. */
00719     NutEventPost(&vol->vol_fsmutex);
00720 
00721     return rc;
00722 }
00723 #endif
00724 
00728 static int RawFsApiFileRead(NUTFILE * nfp, void *buffer, int size)
00729 {
00730     int rc;
00731     RAWVOLUME *vol;
00732 
00733     NUTASSERT(nfp != NULL);
00734     NUTASSERT(nfp->nf_dev != NULL);
00735     vol = (RAWVOLUME *) nfp->nf_dev->dev_dcb;
00736     NUTASSERT(vol != NULL);
00737 
00738     /* Lock filesystem access. */
00739     NutEventWait(&vol->vol_fsmutex, 0);
00740     /* Call worker routine. */
00741     rc = RawFsFileRead(nfp, buffer, size);
00742     /* Release filesystem lock. */
00743     NutEventPost(&vol->vol_fsmutex);
00744 
00745     return rc;
00746 }
00747 
00751 static int RawFsApiIOCtl(NUTDEVICE * dev, int req, void *conf)
00752 {
00753     int rc;
00754     RAWVOLUME *vol;
00755 
00756     NUTASSERT(dev != NULL);
00757     vol = (RAWVOLUME *) dev->dev_dcb;
00758 
00759     /* Lock filesystem access. */
00760     if (req != FS_VOL_MOUNT && vol) {
00761         NutEventWait(&vol->vol_fsmutex, 0);
00762     }
00763     /* Call worker routine. */
00764     rc = RawFsIOCtl(dev, req, conf);
00765     /* Release filesystem lock. */
00766     if (req != FS_VOL_MOUNT && req != FS_VOL_UNMOUNT && vol) {
00767         NutEventPost(&vol->vol_fsmutex);
00768     }
00769     return rc;
00770 }
00771 
00784 NUTDEVICE devRawFs0 = {
00785     0,                      
00786     {'R', 'A', 'W', 'F', 'S', '0', 0, 0, 0}
00787     ,                       
00788     IFTYP_FS,               
00789     0,                      
00790     0,                      
00791     0,                      
00792     0,                      
00793     RawFsInit,              
00794     RawFsApiIOCtl,          
00795     RawFsApiFileRead,       
00796     RawFsApiFileWrite,      
00797 #ifdef __HARVARD_ARCH__
00798     RawFsApiFileWrite_P,    
00799 #endif
00800     RawFsApiFileOpen,       
00801     RawFsApiFileClose,      
00802     RawFsFileSize           
00803 };
00804