Nut/OS  4.10.3
API Reference
blockdev.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008-2009 by egnite GmbH
00003  * Copyright (C) 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 
00045 #include <cfg/os.h>
00046 #include <cfg/memory.h>
00047 
00048 #include <dev/blockdev.h>
00049 #include <sys/nutdebug.h>
00050 #include <fs/fs.h>
00051 
00052 #include <stdlib.h>
00053 #include <errno.h>
00054 #include <memdebug.h>
00055 
00059 typedef struct _BLOCKVOLUME BLOCKVOLUME;
00060 
00064 struct _BLOCKVOLUME {
00067     NUTDEVICE *vol_fsdev;
00068 
00071     uint32_t vol_blk_cnt;
00072 
00075     int vol_blk_len;
00076 
00079     uint32_t vol_blk_off;
00080 
00088     uint32_t vol_blk_num;
00089 
00099     uint8_t *vol_blk_buf;
00100 };
00101 
00109 static NUTDEVICE *NutDeviceLookupType(uint_fast8_t type)
00110 {
00111     NUTDEVICE *dev;
00112 
00113     for (dev = nutDeviceList; dev; dev = dev->dev_next) {
00114         if (dev->dev_type == type) {
00115             break;
00116         }
00117     }
00118     return dev;
00119 }
00120 
00131 int NutBlockDeviceInit(NUTDEVICE * dev)
00132 {
00133     NUTASSERT(dev != NULL);
00134 
00135     return 0;
00136 }
00137 
00163 NUTFILE *NutBlockDeviceOpen(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00164 {
00165     NUTDEVICE *fsdev;
00166 
00167     /* Parse name for a file system driver, skip partition number. */
00168     NUTASSERT(name != NULL);
00169     if (*name) {
00170         do {
00171             name++;
00172         } while (*name && *name != '/');
00173         if (*name == '/') {
00174             name++;
00175         }
00176     }
00177 
00178     /*
00179      * Check the list of registered devices for the given name of the
00180      * files system driver. If none has been specified, get the first
00181      * file system driver in the list. Hopefully the application
00182      * registered one only.
00183      */
00184     if (*name) {
00185         fsdev = NutDeviceLookup(name);
00186     } else {
00187         fsdev = NutDeviceLookupType(IFTYP_FS);
00188     }
00189 
00190     if (fsdev == NULL) {
00191         errno = ENODEV;
00192     } else {
00193         BLOCKVOLUME *fcb = malloc(sizeof(BLOCKVOLUME));
00194 
00195         if (fcb) {
00196             NUTBLOCKIO *blkio;
00197 
00198             NUTASSERT(dev != NULL);
00199 
00200             blkio = (NUTBLOCKIO *) (dev->dev_dcb);
00201             NUTASSERT(blkio != NULL);
00202 
00203             fcb->vol_fsdev = fsdev;
00204             fcb->vol_blk_off = blkio->blkio_vol_bot;
00205             fcb->vol_blk_cnt = blkio->blkio_blk_cnt - blkio->blkio_vol_bot - blkio->blkio_vol_top;
00206             fcb->vol_blk_num = 0;
00207             fcb->vol_blk_len = blkio->blkio_blk_siz;
00208             fcb->vol_blk_buf = malloc(fcb->vol_blk_len);
00209             if (fcb->vol_blk_buf) {
00210                 NUTFILE *nfp = malloc(sizeof(NUTFILE));
00211 
00212                 if (nfp) {
00213                     FSCP_VOL_MOUNT mparm;
00214 
00215                     nfp->nf_next = NULL;
00216                     nfp->nf_dev = dev;
00217                     nfp->nf_fcb = fcb;
00218                     /* Mount the file system volume. */
00219                     mparm.fscp_bmnt = nfp;
00220                     mparm.fscp_part_type = 0;
00221                     if (fsdev->dev_ioctl(fsdev, FS_VOL_MOUNT, &mparm) == 0) {
00222                         /* Successful return. */
00223                         return nfp;
00224                     }
00225                     free(nfp);
00226                 }
00227             }
00228             free(fcb);
00229         }
00230     }
00231     return NUTFILE_EOF;
00232 }
00233 
00241 int NutBlockDeviceClose(NUTFILE * nfp)
00242 {
00243     int rc = -1;
00244     BLOCKVOLUME *fcb;
00245 
00246     NUTASSERT(nfp != NULL);
00247     fcb = (BLOCKVOLUME *) nfp->nf_fcb;
00248     if (fcb) {
00249         NUTASSERT(fcb->vol_fsdev != NULL);
00250         NUTASSERT(fcb->vol_fsdev->dev_ioctl != NULL);
00251         rc = fcb->vol_fsdev->dev_ioctl(fcb->vol_fsdev, FS_VOL_UNMOUNT, NULL);
00252         free(fcb);
00253     }
00254     free(nfp);
00255 
00256     return rc;
00257 }
00258 
00280 int NutBlockDeviceIOCtl(NUTDEVICE * dev, int req, void *conf)
00281 {
00282     int rc = 0;
00283 
00284     switch (req) {
00285     case NUTBLKDEV_SEEK:
00286         {
00287             BLKPAR_SEEK *par = (BLKPAR_SEEK *) conf;
00288             BLOCKVOLUME *fcb;
00289 
00290             /* Sanity check. */
00291             NUTASSERT(conf != NULL);
00292             NUTASSERT(par->par_nfp != NULL);
00293             NUTASSERT(par->par_nfp->nf_fcb != NULL);
00294 
00295             fcb = (BLOCKVOLUME *) par->par_nfp->nf_fcb;
00296             fcb->vol_blk_num = par->par_blknum;
00297         }
00298         break;
00299     case NUTBLKDEV_INFO:
00300         {
00301             BLKPAR_INFO *par;
00302             BLOCKVOLUME *fcb;
00303 
00304             NUTASSERT(conf != NULL);
00305             par = (BLKPAR_INFO *) conf;
00306             NUTASSERT(par->par_nfp != NULL);
00307             NUTASSERT(par->par_nfp->nf_fcb != NULL);
00308             fcb = (BLOCKVOLUME *) par->par_nfp->nf_fcb;
00309 
00310             par->par_nblks = fcb->vol_blk_cnt;
00311             par->par_blksz = fcb->vol_blk_len;
00312             par->par_blkbp = fcb->vol_blk_buf;
00313         }
00314         break;
00315     default:
00316         {
00317             NUTBLOCKIO *blkio;
00318 
00319             NUTASSERT(dev != NULL);
00320             NUTASSERT(dev->dev_dcb != NULL);
00321             blkio = (NUTBLOCKIO *) (dev->dev_dcb);
00322 
00323             NUTASSERT(blkio->blkio_ioctl != NULL);
00324             rc = blkio->blkio_ioctl(dev, req, conf);
00325         }
00326         break;
00327     }
00328     return rc;
00329 }
00330 
00348 int NutBlockDeviceRead(NUTFILE * nfp, void *buffer, int num)
00349 {
00350     int rc;
00351     int cnt;
00352     uint8_t *bp = buffer;
00353     NUTBLOCKIO *blkio;
00354     BLOCKVOLUME *fcb;
00355 
00356     /* Sanity checks. */
00357     if (num == 0) {
00358         return 0;
00359     }
00360     NUTASSERT(buffer != NULL);
00361     NUTASSERT(nfp != NULL);
00362     NUTASSERT(nfp->nf_fcb != NULL);
00363     NUTASSERT(nfp->nf_dev != NULL);
00364     NUTASSERT(nfp->nf_dev->dev_dcb != NULL);
00365 
00366     blkio = nfp->nf_dev->dev_dcb;
00367     fcb = (BLOCKVOLUME *) nfp->nf_fcb;
00368     NUTASSERT(blkio->blkio_read != NULL);
00369 
00370     for (rc = 0; rc < num; rc++) {
00371         if (fcb->vol_blk_num >= fcb->vol_blk_cnt) {
00372             break;
00373         }
00374         cnt = (*blkio->blkio_read) (nfp->nf_dev, fcb->vol_blk_num + fcb->vol_blk_off, bp, fcb->vol_blk_len);
00375         if (cnt != fcb->vol_blk_len) {
00376             break;
00377         }
00378         fcb->vol_blk_num++;
00379         bp += fcb->vol_blk_len;
00380     }
00381     return rc ? rc : -1;
00382 }
00383 
00400 int NutBlockDeviceWrite(NUTFILE * nfp, CONST void *buffer, int num)
00401 {
00402     int rc;
00403     int cnt;
00404     CONST uint8_t *bp = buffer;
00405     NUTBLOCKIO *blkio;
00406     BLOCKVOLUME *fcb;
00407 
00408     /* Sanity checks. */
00409     if (num == 0) {
00410         return 0;
00411     }
00412     NUTASSERT(nfp != NULL);
00413     NUTASSERT(nfp->nf_fcb != NULL);
00414     NUTASSERT(nfp->nf_dev != NULL);
00415     NUTASSERT(nfp->nf_dev->dev_dcb != NULL);
00416 
00417     fcb = (BLOCKVOLUME *) nfp->nf_fcb;
00418     blkio = nfp->nf_dev->dev_dcb;
00419     NUTASSERT(blkio->blkio_write != NULL);
00420 
00421     for (rc = 0; rc < num; rc++) {
00422         if (fcb->vol_blk_num >= fcb->vol_blk_cnt) {
00423             break;
00424         }
00425         cnt = (*blkio->blkio_write) (nfp->nf_dev, fcb->vol_blk_num + fcb->vol_blk_off, bp, fcb->vol_blk_len);
00426         if (cnt != fcb->vol_blk_len) {
00427             break;
00428         }
00429         fcb->vol_blk_num++;
00430         bp += fcb->vol_blk_len;
00431     }
00432     return rc ? rc : -1;
00433 }
00434 
00435 #ifdef __HARVARD_ARCH__
00436 
00452 int NutBlockDeviceWrite_P(NUTFILE * nfp, PGM_P buffer, int num)
00453 {
00454     int rc = 0;
00455     int cnt;
00456     PGM_P bp = buffer;
00457     NUTBLOCKIO *blkio;
00458     BLOCKVOLUME *fcb;
00459 
00460     /* Sanity checks. */
00461     if (num == 0) {
00462         return 0;
00463     }
00464     NUTASSERT(nfp != NULL);
00465     NUTASSERT(nfp->nf_fcb != NULL);
00466     NUTASSERT(nfp->nf_dev != NULL);
00467     NUTASSERT(nfp->nf_dev->dev_dcb != NULL);
00468 
00469     fcb = (BLOCKVOLUME *) nfp->nf_fcb;
00470     blkio = nfp->nf_dev->dev_dcb;
00471     NUTASSERT(blkio->blkio_write != NULL);
00472 
00473     for (rc = 0; rc < num; rc++) {
00474         if (fcb->vol_blk_num >= fcb->vol_blk_cnt) {
00475             break;
00476         }
00477         cnt = (*blkio->blkio_write_P) (nfp->nf_dev, fcb->vol_blk_num + fcb->vol_blk_off, bp, fcb->vol_blk_len);
00478         if (cnt != fcb->vol_blk_len) {
00479             break;
00480         }
00481         fcb->vol_blk_num++;
00482         bp += fcb->vol_blk_len;
00483     }
00484     return rc ? rc : -1;
00485 }
00486 #endif
00487 
00495 long NutBlockDeviceSize(NUTFILE * nfp)
00496 {
00497     BLOCKVOLUME *fcb;
00498 
00499     NUTASSERT(nfp != NULL);
00500     fcb = (BLOCKVOLUME *) nfp->nf_fcb;
00501     NUTASSERT(fcb != NULL);
00502 
00503     return (long) fcb->vol_blk_cnt * (long) fcb->vol_blk_len;
00504 }