Nut/OS  4.10.3
API Reference
uflashfs.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2010 by egnite GmbH
00003  *
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * 1. Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer.
00012  * 2. Redistributions in binary form must reproduce the above copyright
00013  *    notice, this list of conditions and the following disclaimer in the
00014  *    documentation and/or other materials provided with the distribution.
00015  * 3. Neither the name of the copyright holders nor the names of
00016  *    contributors may be used to endorse or promote products derived
00017  *    from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00020  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00021  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00022  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00023  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00024  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00025  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00026  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00027  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00028  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00029  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00030  * SUCH DAMAGE.
00031  *
00032  * For additional information see http://www.ethernut.de/
00033  */
00034 
00035 #include <fs/fs.h>
00036 #include <sys/nutdebug.h>
00037 
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040 #include <fcntl.h>
00041 #include <sys/stat.h>
00042 #include <string.h>
00043 #include <errno.h>
00044 #include <dirent.h>
00045 
00046 #include <dev/spi_at45dib.h>
00047 #include <fs/uflashfs.h>
00048 
00049 #if 0
00050 /* Use for local debugging. */
00051 #define NUTDEBUG
00052 #include <stdio.h>
00053 #endif
00054 
00089 
00090 /* Wheter to use time stamps. Requires, that the system time had been set. */
00091 //#define UFLASH_USE_TIMESTAMP
00092 
00093 /* Wheter to use IDs instead of file names. Not implemented. */
00094 //#define UFLASH_ID_NAMES
00095 
00096 /*
00097  * File system configuration.
00098  */
00099 #ifndef UFLASH_MAX_BLOCKS
00100 
00101 #define UFLASH_MAX_BLOCKS       8192
00102 #endif
00103 
00104 #ifndef UFLASH_BLOCK_UNITS
00105 
00106 #define UFLASH_BLOCK_UNITS      4
00107 #endif
00108 
00109 #ifndef UFLASH_ENTRIES
00110 
00111 #define UFLASH_ENTRIES          128
00112 #endif
00113 
00114 #ifndef UFLASH_USAGE_CACHE
00115 
00116 #define UFLASH_USAGE_CACHE      32
00117 #endif
00118 
00119 #if UFLASH_MAX_BLOCKS <= 255
00120 typedef uint8_t blknum_t;
00121 typedef uint_fast8_t blknum_fast_t;
00122 #elif UFLASH_MAX_BLOCKS <= 65535
00123 typedef uint16_t blknum_t;
00124 typedef uint_fast16_t blknum_fast_t;
00125 #else
00126 typedef uint32_t blknum_t;
00127 typedef uint_fast32_t blknum_fast_t;
00128 #endif
00129 
00130 #ifndef UFLASH_MAX_PATH
00131 
00138 #define UFLASH_MAX_PATH      0
00139 #endif
00140 
00141 #define UFLASH_BLOCK_INVALID    ((blknum_t)-1)
00142 
00146 typedef struct _BLOCK_USAGE {
00147     uint8_t use_cnt;
00148     blknum_t use_phyblk;
00149 } BLOCK_USAGE;
00150 
00154 static BLOCK_USAGE min_used[UFLASH_USAGE_CACHE];
00155 
00161 typedef struct __attribute__ ((packed)) _BLOCKHEAD {
00162     blknum_t bh_logblk;         
00163     blknum_t bh_version;        
00164     blknum_t bh_entblk;         
00165     blknum_t bh_entseq;         
00166 } BLOCKHEAD;
00167 
00173 typedef struct __attribute__ ((packed)) _BLOCKFOOT {
00174 #ifdef UFLASH_USE_TIMESTAMP
00175     time_t bf_time;             
00176 #endif
00177     uint8_t bf_wear;            
00178 } BLOCKFOOT;
00179 
00180 /*
00181  * UFLASH entry header.
00182  *
00183  * On each entry block an ENTRYHEAD structure follows the BLOCKHEAD.
00184  * The ENTRYHEAD is followed by the variable length name of this entry.
00185  * After the name comes the data, immediatly followed by an optional 
00186  * timestamp.
00187  */
00188 typedef struct __attribute__ ((packed)) _ENTRYHEAD {
00189     /* Entry attributes. */
00190     uint8_t eh_attr;
00191     /* Name length. */
00192     uint8_t eh_nlen;
00193 } ENTRYHEAD;
00194 
00198 typedef struct _UFLASHENTRY {
00200     blknum_t ent_id;
00202     uint32_t ent_pos;
00204     blknum_t ent_bidx;
00206     uint16_t ent_sidx;
00208     uint16_t ent_uidx;
00210     uint16_t ent_upos;
00211 
00213     uint32_t ent_mode;
00215     uint8_t ent_attr;
00217     uint8_t ent_namlen;
00219     uint32_t ent_size;
00220 
00222     uint16_t ent_eoff;
00223 } UFLASHENTRY;
00224 
00225 #define UFLASH_VOLF_FIXED       0x80
00226 
00228 typedef struct _UFLASHVOLUME UFLASHVOLUME;
00229 
00233 struct _UFLASHVOLUME {
00235     NUTSERIALFLASH *vol_ifc;
00237     HANDLE vol_mutex;
00239     uint8_t vol_attrib;
00241     blknum_t vol_blocks;
00243     blknum_t *vol_l2p;
00244 };
00245 
00249 typedef struct _UFLASHFIND {
00250     blknum_t uff_lbe;
00251     char *uff_path;
00252 } UFLASHFIND;
00253 
00257 static int FlashUnitCopy(NUTSERIALFLASH * ifc, blknum_t b_src, blknum_t b_dst, sf_unit_t unit)
00258 {
00259     unit += ifc->sf_rsvbot;
00260     return (*ifc->sf_copy) (ifc, b_src * UFLASH_BLOCK_UNITS + unit, b_dst * UFLASH_BLOCK_UNITS + unit);
00261 }
00262 
00266 static void FlashUnitCommit(NUTSERIALFLASH * ifc, blknum_t b, sf_unit_t unit)
00267 {
00268     (*ifc->sf_commit) (ifc, b * UFLASH_BLOCK_UNITS + unit + ifc->sf_rsvbot);
00269 }
00270 
00274 static int FlashUnitRead(NUTSERIALFLASH * ifc, blknum_t b, sf_unit_t unit, int upos, void *data, int len)
00275 {
00276     int rc = ifc->sf_unit_size - upos;
00277 
00278     if (unit == UFLASH_BLOCK_UNITS - 1) {
00279         rc -= sizeof(BLOCKFOOT);
00280     }
00281     if (rc > len) {
00282         rc = len;
00283     }
00284     (*ifc->sf_read) (ifc, b * UFLASH_BLOCK_UNITS + unit + ifc->sf_rsvbot, upos, data, rc);
00285 
00286     return rc;
00287 }
00288 
00292 static int FlashUnitWrite(NUTSERIALFLASH * ifc, blknum_t b, sf_unit_t unit, int upos, CONST void *data, int len)
00293 {
00294     int rc = ifc->sf_unit_size - upos;
00295 
00296     if (unit == UFLASH_BLOCK_UNITS - 1) {
00297         rc -= sizeof(BLOCKFOOT);
00298     }
00299     if (rc > len) {
00300         rc = len;
00301     }
00302     (*ifc->sf_write) (ifc, b * UFLASH_BLOCK_UNITS + unit + ifc->sf_rsvbot, upos, data, rc);
00303 
00304     return rc;
00305 }
00306 
00310 static int FlashCheckBlock(NUTSERIALFLASH * ifc, blknum_t b)
00311 {
00312     return (*ifc->sf_check) (ifc, b * UFLASH_BLOCK_UNITS + ifc->sf_rsvbot, UFLASH_BLOCK_UNITS);
00313 }
00314 
00318 static int FlashReadBlockHead(NUTSERIALFLASH * ifc, blknum_t b, BLOCKHEAD * bh)
00319 {
00320     return (*ifc->sf_read) (ifc, b * UFLASH_BLOCK_UNITS + ifc->sf_rsvbot, 0, bh, sizeof(BLOCKHEAD));
00321 }
00322 
00326 static int FlashWriteBlockHead(NUTSERIALFLASH * ifc, blknum_t b, BLOCKHEAD * bh)
00327 {
00328     /* Update the block's version number. */
00329     bh->bh_version++;
00330     return (*ifc->sf_write) (ifc, b * UFLASH_BLOCK_UNITS + ifc->sf_rsvbot, 0, bh, sizeof(BLOCKHEAD));
00331 }
00332 
00336 static int FlashReadEntry(NUTSERIALFLASH * ifc, blknum_t b, ENTRYHEAD * eh, char **name)
00337 {
00338     int rc;
00339 
00340     /* Read the entry header, which contains the name length. */
00341     rc = (*ifc->sf_read) (ifc, b * UFLASH_BLOCK_UNITS + ifc->sf_rsvbot, sizeof(BLOCKHEAD), eh, sizeof(ENTRYHEAD));
00342     if (rc == 0 && name) {
00343         *name = malloc(eh->eh_nlen + 1);
00344         if (*name == NULL) {
00345             rc = -1;
00346         } else {
00347             *(*name + eh->eh_nlen) = '\0';
00348             rc = (*ifc->sf_read) (ifc, b * UFLASH_BLOCK_UNITS + ifc->sf_rsvbot, sizeof(BLOCKHEAD) + sizeof(ENTRYHEAD), *name,
00349                                   eh->eh_nlen);
00350         }
00351     }
00352     return rc;
00353 }
00354 
00358 static int FlashBlockCmpEntryName(NUTSERIALFLASH * ifc, blknum_t b, CONST char *name, uint8_t len)
00359 {
00360     return (*ifc->sf_compare) (ifc, b * UFLASH_BLOCK_UNITS + ifc->sf_rsvbot, sizeof(BLOCKHEAD) + sizeof(ENTRYHEAD), name, len);
00361 }
00362 
00366 static int FlashWriteEntry(NUTSERIALFLASH * ifc, blknum_t b, CONST ENTRYHEAD * eh, CONST char *name)
00367 {
00368     int rc;
00369 
00370     rc = (*ifc->sf_write) (ifc, b * UFLASH_BLOCK_UNITS + ifc->sf_rsvbot, sizeof(BLOCKHEAD), eh, sizeof(ENTRYHEAD));
00371     if (rc == 0) {
00372         rc = (*ifc->sf_write) (ifc, b * UFLASH_BLOCK_UNITS + ifc->sf_rsvbot, sizeof(BLOCKHEAD) + sizeof(ENTRYHEAD), name,
00373                                eh->eh_nlen);
00374     }
00375     return rc;
00376 }
00377 
00381 static int FlashReadBlockFoot(NUTSERIALFLASH * ifc, blknum_t b, BLOCKFOOT * bf)
00382 {
00383     return (*ifc->sf_read) (ifc, (b + 1) * UFLASH_BLOCK_UNITS - 1 + ifc->sf_rsvbot, -(int) sizeof(BLOCKFOOT), bf,
00384                             sizeof(BLOCKFOOT));
00385 }
00386 
00390 static int FlashWriteBlockFoot(NUTSERIALFLASH * ifc, blknum_t b, BLOCKFOOT * bf)
00391 {
00392     bf->bf_wear++;
00393 #ifdef UFLASH_USE_TIMESTAMP
00394     bf->bf_time = time(NULL);
00395 #endif
00396     return (*ifc->sf_write) (ifc, (b + 1) * UFLASH_BLOCK_UNITS - 1 + ifc->sf_rsvbot, -(int) sizeof(BLOCKFOOT), bf,
00397                              sizeof(BLOCKFOOT));
00398 }
00399 
00403 static int FlashEraseEntry(NUTSERIALFLASH * ifc, blknum_t b)
00404 {
00405     return (*ifc->sf_erase) (ifc, b * UFLASH_BLOCK_UNITS + ifc->sf_rsvbot, 1);
00406 }
00407 
00411 static int FlashEraseBlockData(NUTSERIALFLASH * ifc, blknum_t b)
00412 {
00413     return (*ifc->sf_erase) (ifc, b * UFLASH_BLOCK_UNITS + 1 + ifc->sf_rsvbot, UFLASH_BLOCK_UNITS - 1);
00414 }
00415 
00419 static int FlashEraseBlocks(NUTSERIALFLASH * ifc, int n)
00420 {
00421     return (*ifc->sf_erase) (ifc, ifc->sf_rsvbot, n * UFLASH_BLOCK_UNITS);
00422 }
00423 
00431 static void CollectLeastUsed(UFLASHVOLUME * vol, uint8_t * usage)
00432 {
00433     uint8_t rmin;
00434     uint8_t rmax;
00435     blknum_t b;
00436 
00437     /* Determine the range of values. */
00438     rmin = usage[0];
00439     rmax = rmin;
00440     for (b = 1; b < vol->vol_blocks; b++) {
00441         if (usage[b] < rmin) {
00442             rmin = usage[b];
00443             if (rmax - rmin >= 128) {
00444                 break;
00445             }
00446         } else if (usage[b] > rmax) {
00447             rmax = usage[b];
00448             if (rmax - rmin >= 128) {
00449                 break;
00450             }
00451         }
00452     }
00453 
00454     /*
00455        ** If the range of values is equal or greater than half of the full 
00456        ** range, then some values overflowed. In this case we shift all
00457        ** values by half of the full range to get a consecutive sequence.
00458      */
00459     if (b < vol->vol_blocks) {
00460         rmax = 0;
00461         for (b = 0; b < vol->vol_blocks; b++) {
00462             usage[b] += 128;
00463             if (usage[b] > rmax) {
00464                 rmax = usage[b];
00465             }
00466         }
00467     }
00468 
00469     /*
00470        ** Collect a sorted table of minimums.
00471      */
00472     memset(min_used, 0xff, sizeof(min_used));
00473     for (b = 0; b < vol->vol_blocks; b++) {
00474         int j = UFLASH_USAGE_CACHE - 1;
00475 
00476         if (min_used[j].use_phyblk > vol->vol_blocks || min_used[j].use_cnt > usage[b]) {
00477             while (--j >= 0) {
00478                 if (usage[b] >= min_used[j].use_cnt && min_used[j].use_phyblk < vol->vol_blocks) {
00479                     break;
00480                 }
00481                 min_used[j + 1] = min_used[j];
00482             }
00483             min_used[j + 1].use_cnt = usage[b];
00484             min_used[j + 1].use_phyblk = b;
00485         }
00486     }
00487 }
00488 
00489 static blknum_t PhysBlkAllocate(UFLASHVOLUME * vol, int level);
00490 
00499 static int PhysBlkMove(UFLASHVOLUME * vol, blknum_t src, blknum_t dst)
00500 {
00501     int rc = 0;
00502     BLOCKHEAD bh;
00503     BLOCKFOOT bf;
00504     uint_fast8_t u;
00505 
00506     /* Read the header of the source block. */
00507     FlashReadBlockHead(vol->vol_ifc, src, &bh);
00508     /* Read the footer of the destination block. */
00509     FlashReadBlockFoot(vol->vol_ifc, dst, &bf);
00510     /* Erase the tail of the destination. */
00511     FlashEraseBlockData(vol->vol_ifc, dst);
00512     /* Copy unit by unit. */
00513     for (u = 0; rc == 0 && u < UFLASH_BLOCK_UNITS; u++) {
00514         FlashUnitCopy(vol->vol_ifc, src, dst, u);
00515         /* If this is the first unit, write a new version of the header. */
00516         if (u == 0) {
00517             FlashWriteBlockHead(vol->vol_ifc, dst, &bh);
00518         }
00519         /* If this is the last unit, write back an updated footer. */
00520         else if (u == UFLASH_BLOCK_UNITS - 1) {
00521             FlashWriteBlockFoot(vol->vol_ifc, dst, &bf);
00522         }
00523         /* Commit the unit. */
00524         FlashUnitCommit(vol->vol_ifc, dst, u);
00525     }
00526     /* If all done, erase the first unit of the source block. This will
00527        ** make the block available again. */
00528     FlashEraseEntry(vol->vol_ifc, src);
00529 
00530     return 0;
00531 }
00532 
00538 static blknum_t PhysBlkUnused(UFLASHVOLUME * vol)
00539 {
00540     BLOCKHEAD bh;
00541     blknum_t b;
00542 
00543     for (b = 0; b < vol->vol_blocks; b++) {
00544         FlashReadBlockHead(vol->vol_ifc, b, &bh);
00545         if (bh.bh_logblk >= vol->vol_blocks) {
00546             break;
00547         }
00548     }
00549     return b;
00550 }
00551 
00557 static int PhysBlkRequest(UFLASHVOLUME * vol, int level, blknum_t n)
00558 {
00559     blknum_t b;
00560 
00561     /* Check if this block is in use. */
00562     for (b = 0; b < vol->vol_blocks; b++) {
00563         if (vol->vol_l2p[b] == n) {
00564             blknum_t nn;
00565 
00566             nn = PhysBlkAllocate(vol, level + 1);
00567             if (nn >= vol->vol_blocks) {
00568                 return -1;
00569             }
00570             vol->vol_l2p[b] = nn;
00571             PhysBlkMove(vol, n, nn);
00572             break;
00573         }
00574     }
00575     return 0;
00576 }
00577 
00583 static blknum_t PhysBlkAllocate(UFLASHVOLUME * vol, int level)
00584 {
00585     uint8_t *phy_use;
00586     int i;
00587 
00588     for (;;) {
00589         if (level || min_used[UFLASH_USAGE_CACHE - (UFLASH_USAGE_CACHE / 4)].use_phyblk < vol->vol_blocks) {
00590             for (i = 0; i < UFLASH_USAGE_CACHE; i++) {
00591                 blknum_t n = min_used[i].use_phyblk;
00592 
00593                 if (n < vol->vol_blocks) {
00594                     min_used[i].use_phyblk = UFLASH_BLOCK_INVALID;
00595                     if (PhysBlkRequest(vol, level, n)) {
00596                         return UFLASH_BLOCK_INVALID;
00597                     }
00598                     return n;
00599                 }
00600             }
00601         }
00602         /* Cache exhausted. */
00603         phy_use = calloc(vol->vol_blocks, 1);
00604         if (phy_use == NULL) {
00605             break;
00606         }
00607         for (i = 0; i < vol->vol_blocks; i++) {
00608             BLOCKFOOT bf;
00609 
00610             FlashReadBlockFoot(vol->vol_ifc, i, &bf);
00611             phy_use[i] = bf.bf_wear;
00612         }
00613         for (i = 0; i < vol->vol_blocks; i++) {
00614             if (vol->vol_l2p[i] < vol->vol_blocks) {
00615                 phy_use[vol->vol_l2p[i]] += UFLASH_USAGE_CACHE - 1;
00616             }
00617         }
00618         CollectLeastUsed(vol, phy_use);
00619         free(phy_use);
00620         if (level) {
00621             break;
00622         }
00623     }
00624     return PhysBlkUnused(vol);
00625 }
00626 
00632 static blknum_t LogBlkAllocate(UFLASHVOLUME * vol, blknum_t lb)
00633 {
00634     int lb_last = lb ? vol->vol_blocks : UFLASH_ENTRIES;
00635 
00636     /* Find an unused logical block. */
00637     for (; lb < lb_last; lb++) {
00638         if (vol->vol_l2p[lb] >= vol->vol_blocks) {
00639             /* Found, assign a physical block. */
00640             vol->vol_l2p[lb] = PhysBlkAllocate(vol, 0);
00641             break;
00642         }
00643     }
00644     return lb;
00645 }
00646 
00652 static blknum_t LogBlkReallocate(UFLASHVOLUME * vol, blknum_t lb)
00653 {
00654     blknum_t b_old;
00655     blknum_t b_new;
00656 
00657     /* Allocate a new physical block. Note, that the currently assigned
00658        ** physical block may move during this allocation. */
00659     b_new = PhysBlkAllocate(vol, 0);
00660     if (b_new >= vol->vol_blocks) {
00661         b_old = b_new;
00662     } else {
00663         b_old = vol->vol_l2p[lb];
00664         vol->vol_l2p[lb] = b_new;
00665     }
00666     return b_old;
00667 }
00668 
00674 static int LogBlkRelease(UFLASHVOLUME * vol, blknum_t lb)
00675 {
00676     blknum_t b;
00677 
00678     b = vol->vol_l2p[lb];
00679     vol->vol_l2p[lb] = UFLASH_BLOCK_INVALID;
00680 
00681     return FlashEraseEntry(vol->vol_ifc, b);
00682 }
00683 
00695 static blknum_t EntrySeek(UFLASHVOLUME * vol, blknum_t lbe, blknum_t seq)
00696 {
00697     blknum_t lb = lbe;
00698 
00699     /* Data block sequence 0 is the same as the entry block. No need to
00700        ** search for it. */
00701     if (seq) {
00702         /* Walking through the translation table requires exclusive access. */
00703         NutEventWait(&vol->vol_mutex, 0);
00704         /* No need to search the entry blocks. */
00705         for (lb = UFLASH_ENTRIES; lb < vol->vol_blocks; lb++) {
00706             blknum_t b = vol->vol_l2p[lb];
00707 
00708             /* If this block is allocated, read its header. */
00709             if (b < vol->vol_blocks) {
00710                 BLOCKHEAD bh;
00711 
00712                 FlashReadBlockHead(vol->vol_ifc, b, &bh);
00713                 if (bh.bh_entblk == lbe && bh.bh_entseq == seq) {
00714                     /* Block found. */
00715                     break;
00716                 }
00717             }
00718         }
00719         /* Release the exclusive access. */
00720         NutEventPost(&vol->vol_mutex);
00721     }
00722     return lb;
00723 }
00724 
00728 static void EntryPosSet(NUTFILE * nfp, long pos)
00729 {
00730     uint16_t seq;
00731     uint32_t off;
00732     UFLASHENTRY *ent;
00733     UFLASHVOLUME *vol;
00734 
00735     ent = (UFLASHENTRY *) nfp->nf_fcb;
00736     vol = (UFLASHVOLUME *) nfp->nf_dev->dev_dcb;
00737 
00738     /* Current position within this entry. */
00739     ent->ent_pos = pos;
00740     off = ent->ent_eoff + ent->ent_pos;
00741 
00742     /* Current block sequence within this entry. */
00743     seq = (uint16_t) (off / (vol->vol_ifc->sf_unit_size * UFLASH_BLOCK_UNITS - (sizeof(BLOCKHEAD) + sizeof(BLOCKFOOT))));
00744     if (seq != ent->ent_sidx) {
00745         ent->ent_sidx = seq;
00746         ent->ent_bidx = UFLASH_BLOCK_INVALID;
00747     }
00748 
00749     off -= ent->ent_sidx * (vol->vol_ifc->sf_unit_size * UFLASH_BLOCK_UNITS - (sizeof(BLOCKHEAD) + sizeof(BLOCKFOOT)));
00750 
00751     /* Page number within the current block. */
00752     ent->ent_uidx = (uint16_t) ((off + sizeof(BLOCKHEAD)) / vol->vol_ifc->sf_unit_size);
00753     off -= ent->ent_uidx * vol->vol_ifc->sf_unit_size;
00754 
00755     /* Position with the current page. */
00756     ent->ent_upos = (uint16_t) off + sizeof(BLOCKHEAD);
00757 }
00758 
00759 static void EntryPosInc(NUTFILE * nfp, int step)
00760 {
00761     UFLASHENTRY *ent;
00762     UFLASHVOLUME *vol;
00763 
00764     ent = (UFLASHENTRY *) nfp->nf_fcb;
00765     vol = (UFLASHVOLUME *) nfp->nf_dev->dev_dcb;
00766 
00767     ent->ent_pos += step;
00768     ent->ent_upos += step;
00769     if (ent->ent_uidx < UFLASH_BLOCK_UNITS - 1) {
00770         step = vol->vol_ifc->sf_unit_size - ent->ent_upos;
00771     } else {
00772         step = vol->vol_ifc->sf_unit_size - sizeof(BLOCKFOOT) - ent->ent_upos;
00773     }
00774     if (step == 0) {
00775         ent->ent_uidx++;
00776         if (ent->ent_uidx >= UFLASH_BLOCK_UNITS) {
00777             ent->ent_upos = sizeof(BLOCKHEAD);
00778             ent->ent_uidx = 0;
00779             ent->ent_sidx++;
00780             ent->ent_bidx = UFLASH_BLOCK_INVALID;
00781         } else {
00782             ent->ent_upos = 0;
00783         }
00784     }
00785 }
00786 
00792 static long EntryScan(UFLASHVOLUME * vol, blknum_t lbe, time_t * mod)
00793 {
00794     long siz;
00795     int p;
00796     int i;
00797     int off;
00798     BLOCKHEAD bh;
00799     blknum_t lb;
00800     blknum_t lbs = lbe;
00801     blknum_t seq = 0;
00802 
00803 #ifdef UFLASH_USE_TIMESTAMP
00804     if (mod) {
00805         BLOCKFOOT bf;
00806 
00807         FlashReadBlockFoot(vol->vol_ifc, vol->vol_l2p[lbe] / UFLASH_BLOCK_UNITS, &bf);
00808         *mod = bf.bf_time;
00809     }
00810 #endif
00811 
00812     /* Find the highest sequence block. */
00813     for (lb = UFLASH_ENTRIES; lb < vol->vol_blocks; lb++) {
00814         p = vol->vol_l2p[lb];
00815         if (p < vol->vol_blocks) {
00816             p *= UFLASH_BLOCK_UNITS;
00817             FlashReadBlockHead(vol->vol_ifc, p / UFLASH_BLOCK_UNITS, &bh);
00818             if (bh.bh_entblk == lbe) {
00819                 if (seq < bh.bh_entseq) {
00820                     seq = bh.bh_entseq;
00821                     lbs = lb;
00822                 }
00823 #ifdef UFLASH_USE_TIMESTAMP
00824                 if (mod) {
00825                     BLOCKFOOT bf;
00826 
00827                     FlashReadBlockFoot(vol->vol_ifc, p / UFLASH_BLOCK_UNITS, &bf);
00828                     if (*mod < bf.bf_time) {
00829                         *mod = bf.bf_time;
00830                     }
00831                 }
00832 #endif
00833             }
00834         }
00835     }
00836     /* Size of full blocks. */
00837     siz = seq * (vol->vol_ifc->sf_unit_size * UFLASH_BLOCK_UNITS - (sizeof(BLOCKHEAD) + sizeof(BLOCKFOOT)));
00838 
00839     /* Number of bytes in the highest sequence block. */
00840     p = vol->vol_l2p[lbs] * UFLASH_BLOCK_UNITS;
00841     off = -(int) sizeof(BLOCKFOOT);
00842     for (i = UFLASH_BLOCK_UNITS; --i >= 0;) {
00843         int s = (*vol->vol_ifc->sf_used) (vol->vol_ifc, p + i + vol->vol_ifc->sf_rsvbot, off);
00844 
00845         off = 0;
00846         if (s) {
00847             siz += s + i * vol->vol_ifc->sf_unit_size - sizeof(BLOCKHEAD);
00848             break;
00849         }
00850     }
00851     return siz;
00852 }
00853 
00869 static int EntrySearchNext(UFLASHVOLUME * vol, CONST char *name, ENTRYHEAD * eh, blknum_t lbs)
00870 {
00871     blknum_t lbe;
00872     blknum_t b;
00873     int nlen;
00874 
00875     nlen = strlen(name);
00876     /* Walking through the translation table requires exclusive access. */
00877     NutEventWait(&vol->vol_mutex, 0);
00878     for (lbe = lbs == UFLASH_ENTRIES ? 0 : lbs; lbe < UFLASH_ENTRIES; lbe++) {
00879         b = vol->vol_l2p[lbe];
00880         if (b < vol->vol_blocks) {
00881             /* Read the entry header, which contains the path length. */
00882             if (FlashReadEntry(vol->vol_ifc, b, eh, NULL) == 0) {
00883                 /* If the path lengths are equal, then compare the names. */
00884                 if (eh->eh_nlen == nlen || (lbs != UFLASH_ENTRIES && eh->eh_nlen >= nlen)) {
00885                     if (FlashBlockCmpEntryName(vol->vol_ifc, b, name, nlen) == 0) {
00886                         NutEventPost(&vol->vol_mutex);
00887                         return lbe;
00888                     }
00889                 }
00890             }
00891         }
00892     }
00893     NutEventPost(&vol->vol_mutex);
00894     return UFLASH_ENTRIES;
00895 }
00896 
00902 static int EntrySearch(UFLASHVOLUME * vol, CONST char *name, ENTRYHEAD * eh)
00903 {
00904     return EntrySearchNext(vol, name, eh, UFLASH_ENTRIES);
00905 }
00906 
00912 static int EntryTruncateSeq(UFLASHVOLUME * vol, int lbe)
00913 {
00914     blknum_t lb;
00915     BLOCKHEAD bh;
00916 
00917     for (lb = UFLASH_ENTRIES; lb < vol->vol_blocks; lb++) {
00918         if (vol->vol_l2p[lb] < vol->vol_blocks) {
00919             FlashReadBlockHead(vol->vol_ifc, vol->vol_l2p[lb], &bh);
00920             if (bh.bh_entblk == lbe) {
00921                 LogBlkRelease(vol, lb);
00922             }
00923         }
00924     }
00925     return 0;
00926 }
00927 
00933 static int EntryTruncate(UFLASHVOLUME * vol, blknum_t lbe)
00934 {
00935     BLOCKHEAD bh;
00936     ENTRYHEAD eh;
00937     BLOCKFOOT bf;
00938     blknum_t b;
00939     blknum_t b_old;
00940     char *name = NULL;
00941 
00942     EntryTruncateSeq(vol, lbe);
00943 
00944     /* Allocate a new entry block. */
00945     b = PhysBlkAllocate(vol, 0);
00946     if (b >= vol->vol_blocks) {
00947         return -1;
00948     }
00949     b_old = vol->vol_l2p[lbe];
00950 
00951     vol->vol_l2p[lbe] = b;
00952 
00953     /* Read the block footer and erase the remaining units. */
00954     FlashReadBlockFoot(vol->vol_ifc, b, &bf);
00955     FlashEraseBlockData(vol->vol_ifc, b);
00956 
00957     /* Copy block and entry headers, incrementing the version.
00958      * Note, that we cannot use a unit copy, because we also must
00959      * get rid of the data in the first block. */
00960     FlashReadBlockHead(vol->vol_ifc, b_old, &bh);
00961     FlashReadEntry(vol->vol_ifc, b_old, &eh, &name);
00962     FlashWriteBlockHead(vol->vol_ifc, b, &bh);
00963     FlashWriteEntry(vol->vol_ifc, b, &eh, name);
00964     FlashUnitCommit(vol->vol_ifc, b, 0);
00965 
00966     /* Update block footer in the last unit. */
00967     FlashWriteBlockFoot(vol->vol_ifc, b, &bf);
00968     FlashUnitCommit(vol->vol_ifc, b, UFLASH_BLOCK_UNITS - 1);
00969 
00970     /* Remove the old entry. */
00971     FlashEraseEntry(vol->vol_ifc, b_old);
00972 
00973     return 0;
00974 }
00975 
00981 static int EntryCreate(UFLASHVOLUME * vol, blknum_t lbe, ENTRYHEAD * eh, CONST char *name)
00982 {
00983     BLOCKHEAD bh;
00984     BLOCKFOOT bf;
00985     blknum_t b;
00986 
00987     b = vol->vol_l2p[lbe];
00988 
00989     /* Read the footer before erasing the block. */
00990     FlashReadBlockFoot(vol->vol_ifc, b, &bf);
00991     FlashEraseBlockData(vol->vol_ifc, b);
00992 
00993     /* Write block header. */
00994     bh.bh_logblk = lbe;
00995     bh.bh_version = UFLASH_BLOCK_INVALID;
00996     bh.bh_entblk = lbe;
00997     bh.bh_entseq = 0;
00998     FlashWriteBlockHead(vol->vol_ifc, b, &bh);
00999 
01000     /* Write the entry header and name. */
01001     FlashWriteEntry(vol->vol_ifc, b, eh, name);
01002     FlashUnitCommit(vol->vol_ifc, b, 0);
01003 
01004     /* Update block footer. */
01005     FlashWriteBlockFoot(vol->vol_ifc, b, &bf);
01006     FlashUnitCommit(vol->vol_ifc, b, UFLASH_BLOCK_UNITS - 1);
01007 
01008     return 0;
01009 }
01010 
01014 static int UFlashFileRemove(NUTDEVICE * dev, CONST char *name)
01015 {
01016     blknum_t lbe;
01017     ENTRYHEAD eh;
01018     UFLASHVOLUME *vol;
01019 
01020     vol = (UFLASHVOLUME *) dev->dev_dcb;
01021 
01022     while (*name == '/') {
01023         name++;
01024     }
01025     lbe = EntrySearch(vol, name, &eh);
01026     if (lbe >= UFLASH_ENTRIES || vol->vol_l2p[lbe] > vol->vol_blocks) {
01027         return -1;
01028     }
01029     NutEventWait(&vol->vol_mutex, 0);
01030     EntryTruncateSeq(vol, lbe);
01031     LogBlkRelease(vol, lbe);
01032     NutEventPost(&vol->vol_mutex);
01033 
01034     return 0;
01035 }
01036 
01040 static int UFlashFileStatus(NUTDEVICE * dev, CONST char *name, struct stat *st)
01041 {
01042     blknum_t lbe;
01043     ENTRYHEAD eh;
01044     UFLASHVOLUME *vol;
01045     uint_fast8_t partial = 0;
01046 
01047     vol = (UFLASHVOLUME *) dev->dev_dcb;
01048 
01049     while (*name == '/') {
01050         name++;
01051     }
01052     lbe = EntrySearch(vol, name, &eh);
01053     if (lbe >= UFLASH_ENTRIES || vol->vol_l2p[lbe] > vol->vol_blocks) {
01054         lbe = EntrySearchNext(vol, name, &eh, 0);
01055         if (lbe >= UFLASH_ENTRIES || vol->vol_l2p[lbe] > vol->vol_blocks) {
01056             return -1;
01057         }
01058         partial = 1;
01059     }
01060     memset(st, 0, sizeof(struct stat));
01061     if (partial) {
01062         st->st_mode = 1;
01063 #ifdef UFLASH_USE_TIMESTAMP
01064         EntryScan(vol, lbe, &st->st_mtime);
01065 #endif
01066     } else {
01067         NutEventWait(&vol->vol_mutex, 0);
01068 #ifdef UFLASH_USE_TIMESTAMP
01069         st->st_size = EntryScan(vol, lbe, &st->st_mtime);
01070 #else
01071         st->st_size = EntryScan(vol, lbe, NULL);
01072 #endif
01073         NutEventPost(&vol->vol_mutex);
01074 #if UFLASH_MAX_PATH
01075         st->st_size -= sizeof(ENTRYHEAD) + UFLASH_MAX_PATH;
01076 #else
01077         st->st_size -= sizeof(ENTRYHEAD) + eh.eh_nlen;
01078 #endif
01079     }
01080     return 0;
01081 }
01082 
01091 static NUTFILE *UFlashDirOpen(NUTDEVICE * dev, CONST char *dpath)
01092 {
01093     NUTFILE *ndp;
01094     UFLASHFIND *uff;
01095 
01096     ndp = malloc(sizeof(NUTFILE));
01097     if (ndp) {
01098         uff = malloc(sizeof(UFLASHFIND));
01099         if (uff) {
01100             uff->uff_lbe = 0;
01101             uff->uff_path = strdup(dpath + (*dpath == '/'));
01102             if (uff->uff_path) {
01103                 ndp->nf_dev = dev;
01104                 ndp->nf_fcb = uff;
01105 
01106                 return ndp;
01107             }
01108             free(uff);
01109         }
01110         free(ndp);
01111     }
01112     return NUTFILE_EOF;
01113 }
01114 
01118 static int UFlashDirClose(NUTFILE * ndp)
01119 {
01120     UFLASHFIND *uff;
01121 
01122     uff = (UFLASHFIND *) ndp->nf_fcb;
01123     free(uff->uff_path);
01124     free(uff);
01125     free(ndp);
01126 
01127     return 0;
01128 }
01129 
01133 static int UFlashDirRead(DIR * dir)
01134 {
01135     struct dirent *ent;
01136     NUTFILE *ndp;
01137     NUTDEVICE *dev;
01138     UFLASHFIND *uff;
01139     UFLASHVOLUME *vol;
01140     ENTRYHEAD eh;
01141     char *name = NULL;
01142     char *cp;
01143 
01144     ndp = dir->dd_fd;
01145     uff = (UFLASHFIND *) ndp->nf_fcb;
01146     dev = ndp->nf_dev;
01147     vol = (UFLASHVOLUME *) dev->dev_dcb;
01148 
01149     uff->uff_lbe = EntrySearchNext(vol, uff->uff_path, &eh, uff->uff_lbe);
01150     if (uff->uff_lbe >= UFLASH_ENTRIES) {
01151         return -1;
01152     }
01153 
01154     ent = (struct dirent *) dir->dd_buf;
01155     memset(dir->dd_buf, 0, sizeof(struct dirent));
01156     FlashReadEntry(vol->vol_ifc, vol->vol_l2p[uff->uff_lbe], &eh, &name);
01157     cp = strchr(name + strlen(uff->uff_path), '/');
01158     if (cp) {
01159         *cp = '\0';
01160         ent->d_type = 1;
01161     } else {
01162         ent->d_type = 0;
01163     }
01164     strcpy(ent->d_name, name + strlen(uff->uff_path));
01165     ent->d_namlen = strlen(name + strlen(uff->uff_path));
01166     free(name);
01167 
01168     uff->uff_lbe++;
01169 
01170     return 0;
01171 }
01172 
01182 static int UFlashFileRename(NUTDEVICE * dev, CONST char *old_path, CONST char *new_path)
01183 {
01184     blknum_t lbe;
01185     blknum_t b;
01186     blknum_t b_old;
01187     uint_fast8_t u;
01188     ENTRYHEAD eh;
01189     UFLASHVOLUME *vol;
01190     BLOCKHEAD bh;
01191     BLOCKFOOT bf;
01192 
01193     NUTASSERT(dev != NULL);
01194     NUTASSERT(old_path != NULL);
01195 #if UFLASH_MAX_PATH
01196     NUTASSERT(strlen(old_path) <= UFLASH_MAX_PATH);
01197 #endif
01198     NUTASSERT(new_path != NULL);
01199 #if UFLASH_MAX_PATH
01200     NUTASSERT(strlen(new_path) <= UFLASH_MAX_PATH);
01201 #endif
01202     vol = (UFLASHVOLUME *) dev->dev_dcb;
01203     NUTASSERT(vol != NULL);
01204 
01205     vol = (UFLASHVOLUME *) dev->dev_dcb;
01206 
01207     while (*old_path == '/') {
01208         old_path++;
01209     }
01210     while (*new_path == '/') {
01211         new_path++;
01212     }
01213     lbe = EntrySearch(vol, old_path, &eh);
01214     if (lbe >= UFLASH_ENTRIES || vol->vol_l2p[lbe] > vol->vol_blocks) {
01215         return -1;
01216     }
01217 #if UFLASH_MAX_PATH == 0
01218     if (eh.eh_nlen < strlen(new_path)) {
01219         return -1;
01220     }
01221 #endif
01222     eh.eh_nlen = strlen(new_path);
01223 
01224     /* Exclusive access from here. */
01225     NutEventWait(&vol->vol_mutex, 0);
01226 
01227     /* Allocate a new entry block. */
01228     b = PhysBlkAllocate(vol, 0);
01229     if (b >= vol->vol_blocks) {
01230         /* No more blocks available. */
01231         NutEventPost(&vol->vol_mutex);
01232         return -1;
01233     }
01234 
01235     /* Replace the physical block in the translation table. */
01236     b_old = vol->vol_l2p[lbe];
01237     vol->vol_l2p[lbe] = b;
01238 
01239     /* Keep the footer and erase the pages of the new block, except the 
01240        first. The first page of unallocated blocks is already erased. */
01241     FlashReadBlockFoot(vol->vol_ifc, b, &bf);
01242     FlashEraseBlockData(vol->vol_ifc, b);
01243 
01244     /* Copy all pages of the entry block. */
01245     for (u = 0; u < UFLASH_BLOCK_UNITS; u++) {
01246         FlashUnitCopy(vol->vol_ifc, b_old, b, u);
01247         /* If this is the first unit, write a new version of the header. */
01248         if (u == 0) {
01249             /* Separately copy the block header, because this will 
01250                increment the block's version number. */
01251             FlashReadBlockHead(vol->vol_ifc, b, &bh);
01252             FlashWriteBlockHead(vol->vol_ifc, b, &bh);
01253 
01254             /* Fill in the new path name. */
01255             FlashWriteEntry(vol->vol_ifc, b, &eh, new_path);
01256         }
01257         /* If this is the last unit, write back an updated footer. */
01258         else if (u == UFLASH_BLOCK_UNITS - 1) {
01259             FlashWriteBlockFoot(vol->vol_ifc, b, &bf);
01260         }
01261         /* Commit the unit. */
01262         FlashUnitCommit(vol->vol_ifc, b, u);
01263     }
01264 
01265     /* Finally remove the old entry. */
01266     FlashEraseEntry(vol->vol_ifc, b_old);
01267 
01268     /* Release exclusive access. */
01269     NutEventPost(&vol->vol_mutex);
01270 
01271     return 0;
01272 }
01273 
01285 static long UFlashFileSize(NUTFILE * nfp)
01286 {
01287     NUTASSERT(nfp != NULL);
01288     NUTASSERT(nfp->nf_fcb != NULL);
01289 
01290     return ((UFLASHENTRY *) nfp->nf_fcb)->ent_size;
01291 }
01292 
01306 static NUTFILE *UFlashFileOpen(NUTDEVICE * dev, CONST char *path, int mode, int acc)
01307 {
01308     int rc = -1;
01309     NUTFILE *nfp = NUTFILE_EOF;
01310     UFLASHENTRY *ent;
01311     UFLASHVOLUME *vol;
01312     blknum_t lbe;
01313     ENTRYHEAD eh;
01314     long datsiz = 0;
01315 
01316     NUTASSERT(dev != NULL);
01317     NUTASSERT(path != NULL);
01318     vol = (UFLASHVOLUME *) dev->dev_dcb;
01319     NUTASSERT(vol != NULL);
01320 
01321     while (*path == '/') {
01322         path++;
01323     }
01324     /* Allocate a private entry information structure. */
01325     ent = calloc(1, sizeof(UFLASHENTRY));
01326     if (ent == NULL) {
01327         return NUTFILE_EOF;
01328     }
01329     ent->ent_mode = mode;
01330 
01331     lbe = EntrySearch(vol, path, &eh);
01332 
01333     NutEventWait(&vol->vol_mutex, 0);
01334     /* 
01335        ** Entry exists. 
01336      */
01337     if (lbe < UFLASH_ENTRIES) {
01338         if ((mode & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL)) {
01339             errno = EEXIST;
01340         } else {
01341             /* Truncate. */
01342             if ((mode & _O_TRUNC) == _O_TRUNC) {
01343                 rc = EntryTruncate(vol, lbe);
01344             }
01345             /* Do not truncate. */
01346             else {
01347                 rc = 0;
01348                 datsiz = EntryScan(vol, lbe, NULL);
01349 #if UFLASH_MAX_PATH
01350                 datsiz -= sizeof(ENTRYHEAD) + UFLASH_MAX_PATH;
01351 #else
01352                 datsiz -= sizeof(ENTRYHEAD) + eh.eh_nlen;
01353 #endif
01354             }
01355         }
01356     }
01357 
01358     /*
01359        ** Entry doesn't exist.
01360      */
01361     else {
01362         if ((mode & _O_CREAT) == _O_CREAT) {
01363             lbe = LogBlkAllocate(vol, 0);
01364             if (lbe < UFLASH_ENTRIES) {
01365                 eh.eh_nlen = strlen(path);
01366                 eh.eh_attr = 0;
01367                 rc = EntryCreate(vol, lbe, &eh, path);
01368             }
01369         } else {
01370             errno = ENOENT;
01371         }
01372     }
01373 
01374     if (rc) {
01375         free(ent);
01376     } else {
01377         ent->ent_attr = eh.eh_attr;
01378         ent->ent_namlen = eh.eh_nlen;
01379 #if UFLASH_MAX_PATH
01380         ent->ent_eoff = sizeof(ENTRYHEAD) + UFLASH_MAX_PATH;
01381 #else
01382         ent->ent_eoff = sizeof(ENTRYHEAD) + eh.eh_nlen;
01383 #endif
01384         ent->ent_id = lbe;
01385         ent->ent_size = datsiz;
01386 
01387         /* Allocate a file information structure. */
01388         nfp = malloc(sizeof(NUTFILE));
01389         if (nfp == NULL) {
01390             free(ent);
01391             NutEventPost(&vol->vol_mutex);
01392             return NUTFILE_EOF;
01393         }
01394         nfp->nf_next = NULL;
01395         nfp->nf_dev = dev;
01396         nfp->nf_fcb = ent;
01397 
01398         if ((mode & _O_APPEND) == _O_APPEND) {
01399             ent->ent_bidx = UFLASH_BLOCK_INVALID;
01400             EntryPosSet(nfp, datsiz);
01401         } else {
01402             ent->ent_bidx = lbe;
01403             EntryPosSet(nfp, 0);
01404         }
01405     }
01406     NutEventPost(&vol->vol_mutex);
01407     return nfp;
01408 }
01409 
01418 static int UFlashFileClose(NUTFILE * nfp)
01419 {
01420     NUTASSERT(nfp != NULL);
01421     NUTASSERT(nfp->nf_dev != NULL);
01422     NUTASSERT(nfp->nf_fcb != NULL);
01423 
01424     free(nfp->nf_fcb);
01425     free(nfp);
01426 
01427     return 0;
01428 }
01429 
01441 static int UFlashFileRead(NUTFILE * nfp, void *data, int size)
01442 {
01443     int u;
01444     int step;
01445     int rc;
01446     uint8_t *dptr;
01447     UFLASHENTRY *ent;
01448     UFLASHVOLUME *vol;
01449 
01450     /* Ignore input flush. */
01451     if (data == NULL || size == 0) {
01452         return 0;
01453     }
01454     dptr = (uint8_t *) data;
01455 
01456     NUTASSERT(nfp != NULL);
01457     NUTASSERT(nfp->nf_dev != NULL);
01458     ent = (UFLASHENTRY *) nfp->nf_fcb;
01459     NUTASSERT(ent != NULL);
01460     vol = (UFLASHVOLUME *) nfp->nf_dev->dev_dcb;
01461     NUTASSERT(vol != NULL);
01462 
01463     /* Do not read beyond the file end. */
01464     if (size > (int) (ent->ent_size - ent->ent_pos)) {
01465         size = (int) (ent->ent_size - ent->ent_pos);
01466     }
01467 
01468     /*
01469        ** Loop until we read the requested size.
01470      */
01471     for (rc = 0; rc < size;) {
01472         /* Is the current logical block number still valid? */
01473         if (ent->ent_bidx >= vol->vol_blocks) {
01474             /* If not, seek for the right block. */
01475             ent->ent_bidx = EntrySeek(vol, ent->ent_id, ent->ent_sidx);
01476             if (ent->ent_bidx >= vol->vol_blocks) {
01477                 /* Seek failed. */
01478                 errno = EIO;
01479                 return -1;
01480             }
01481         }
01482         /* Read unit by unit. */
01483         for (u = ent->ent_uidx; rc < size && u < UFLASH_BLOCK_UNITS; u++) {
01484             NutEventWait(&vol->vol_mutex, 0);
01485             step = FlashUnitRead(vol->vol_ifc, vol->vol_l2p[ent->ent_bidx], u, ent->ent_upos, dptr, size - rc);
01486             NutEventPost(&vol->vol_mutex);
01487             if (step < 0) {
01488                 /* Read failed. */
01489                 errno = EIO;
01490                 return -1;
01491             }
01492             /* Increment pointers and indices. */
01493             rc += step;
01494             dptr += step;
01495             EntryPosInc(nfp, step);
01496         }
01497     }
01498     return rc;
01499 }
01500 
01513 static int UFlashFileWrite(NUTFILE * nfp, CONST void *data, int len)
01514 {
01515     int u;
01516     blknum_t b;
01517     blknum_t b_old;
01518     int step;
01519     int siz = len;
01520     uint8_t *dptr;
01521     BLOCKHEAD bh;
01522     BLOCKFOOT bf;
01523     UFLASHENTRY *ent;
01524     UFLASHVOLUME *vol;
01525 
01526     /* Ignore output flush. */
01527     if (data == NULL || len == 0) {
01528         return 0;
01529     }
01530     dptr = (uint8_t *) data;
01531 
01532     /* Sanity check. */
01533     NUTASSERT(nfp != NULL);
01534     NUTASSERT(nfp->nf_fcb != NULL);
01535     NUTASSERT(nfp->nf_dev != NULL);
01536     NUTASSERT(nfp->nf_dev->dev_dcb != NULL);
01537 
01538     ent = (UFLASHENTRY *) nfp->nf_fcb;
01539     vol = (UFLASHVOLUME *) nfp->nf_dev->dev_dcb;
01540 
01541     /*
01542        ** Loop until all data has been written.
01543      */
01544     while (len) {
01545         /* Is the current logical block number still valid? */
01546         if (ent->ent_bidx >= vol->vol_blocks) {
01547             /* If not, seek for the right block. The routine will return an
01548                ** invalid block number, if we need a new block. */
01549             ent->ent_bidx = EntrySeek(vol, ent->ent_id, ent->ent_sidx);
01550         }
01551 
01552         /*
01553            ** If the current logical block exists, then we reallocate a
01554            ** physical block.
01555          */
01556         NutEventWait(&vol->vol_mutex, 0);
01557         if (ent->ent_bidx < vol->vol_blocks) {
01558             b_old = LogBlkReallocate(vol, ent->ent_bidx);
01559             if (b_old >= vol->vol_blocks) {
01560                 /* No more blocks available. */
01561                 NutEventPost(&vol->vol_mutex);
01562                 return -1;
01563             }
01564             /* Read header of old block and increment the version number. */
01565             FlashReadBlockHead(vol->vol_ifc, b_old, &bh);
01566         }
01567 
01568         /*
01569            ** If the current logical block doesn't exists, then we allocate
01570            ** a new one.
01571          */
01572         else {
01573             ent->ent_bidx = LogBlkAllocate(vol, UFLASH_ENTRIES);
01574             if (ent->ent_bidx >= vol->vol_blocks) {
01575                 /* No more blocks available. */
01576                 NutEventPost(&vol->vol_mutex);
01577                 return -1;
01578             }
01579             /* No reallocation, old and new are the same block. */
01580             b_old = vol->vol_l2p[ent->ent_bidx];
01581             /* Initial block header. */
01582             bh.bh_logblk = ent->ent_bidx;
01583             bh.bh_entblk = ent->ent_id;
01584             bh.bh_entseq = ent->ent_sidx;
01585             bh.bh_version = UFLASH_BLOCK_INVALID;
01586         }
01587         /* Current physical block. */
01588         b = vol->vol_l2p[ent->ent_bidx];
01589 
01590         /* Read the block footer. */
01591         FlashReadBlockFoot(vol->vol_ifc, b, &bf);
01592         /* The first unit had been erased when the block was released.
01593            ** Now erase the remaining units. */
01594         FlashEraseBlockData(vol->vol_ifc, b);
01595 
01596         /* 
01597            ** Write unit by unit.
01598          */
01599         for (u = 0; u < UFLASH_BLOCK_UNITS; u++) {
01600             /* Make a copy of the old unit. If old and new are
01601                ** the same, this won't hurt. */
01602             FlashUnitCopy(vol->vol_ifc, b_old, b, u);
01603             /* Write the block header to the first unit. */
01604             if (u == 0) {
01605                 FlashWriteBlockHead(vol->vol_ifc, b, &bh);
01606             }
01607             /* If this is the current unit to write to, fill it with data. */
01608             if (len && u == ent->ent_uidx) {
01609                 step = FlashUnitWrite(vol->vol_ifc, b, u, ent->ent_upos, dptr, len);
01610                 /* Increment pointers and indices. */
01611                 len -= step;
01612                 dptr += step;
01613                 EntryPosInc(nfp, step);
01614                 if (ent->ent_size < ent->ent_pos) {
01615                     ent->ent_size = ent->ent_pos;
01616                 }
01617             }
01618             /* Write the block footer to the last unit. */
01619             if (u == UFLASH_BLOCK_UNITS - 1) {
01620                 FlashWriteBlockFoot(vol->vol_ifc, b, &bf);
01621             }
01622             FlashUnitCommit(vol->vol_ifc, b, u);
01623         }
01624         /* If we reallocated the block, then release the old one now.
01625            ** It is essential to do this after having successfully written
01626            ** the new block. If the new block with a higher version number
01627            ** remains incomplete, then the old version still exists and the
01628            ** incomplete block will be removed during mounting. */
01629         if (b != b_old) {
01630             FlashEraseEntry(vol->vol_ifc, b_old);
01631         }
01632         NutEventPost(&vol->vol_mutex);
01633     }
01634     return siz;
01635 }
01636 
01637 #ifdef __HARVARD_ARCH__
01638 
01655 static int UFlashFileWrite_P(NUTFILE * nfp, PGM_P buffer, int len)
01656 {
01657     return -1;
01658 }
01659 #endif
01660 
01673 static int UFlashFileSeek(NUTFILE * nfp, long *pos, int whence)
01674 {
01675     int rc = 0;
01676     long npos;
01677     UFLASHENTRY *ent;
01678 
01679     NUTASSERT(nfp != NULL);
01680     NUTASSERT(nfp->nf_fcb != NULL);
01681 
01682     ent = (UFLASHENTRY *) nfp->nf_fcb;
01683 
01684     NUTASSERT(pos != NULL);
01685     npos = *pos;
01686 
01687     switch (whence) {
01688     case SEEK_CUR:
01689         /* Relative to current position. */
01690         npos += ent->ent_pos;
01691         break;
01692     case SEEK_END:
01693         /* Relative to file end. */
01694         npos += ent->ent_size;
01695         break;
01696     }
01697 
01698     /* Make sure that we are within limits. */
01699     if (npos < 0 || npos > (long) ent->ent_size) {
01700         errno = EINVAL;
01701         rc = -1;
01702     } else {
01703         EntryPosSet(nfp, npos);
01704         *pos = npos;
01705     }
01706     return rc;
01707 }
01708 
01716 static int UFlashMount(NUTDEVICE * dev)
01717 {
01718     int b;
01719     BLOCKHEAD bh;
01720     UFLASHVOLUME *vol;
01721 
01722     NUTASSERT(dev != NULL);
01723     NUTASSERT(dev->dev_icb != NULL);
01724     NUTASSERT(dev->dev_dcb == NULL);
01725 
01726     /* Allocate the volume information structure  */
01727     vol = calloc(1, sizeof(UFLASHVOLUME));
01728     if (vol == NULL) {
01729         return -1;
01730     }
01731     dev->dev_dcb = vol;
01732     vol->vol_ifc = (NUTSERIALFLASH *) dev->dev_icb;
01733 
01734     /* Determine the total number of blocks. Honor any reserved units. */
01735     vol->vol_blocks =
01736         (blknum_t) ((vol->vol_ifc->sf_units - vol->vol_ifc->sf_rsvbot - vol->vol_ifc->sf_rsvtop) / UFLASH_BLOCK_UNITS);
01737     if (vol->vol_blocks > UFLASH_MAX_BLOCKS) {
01738         vol->vol_blocks = UFLASH_MAX_BLOCKS;
01739     }
01740 
01741     /* Allocate the block translation table. */
01742     vol->vol_l2p = malloc(vol->vol_blocks * sizeof(blknum_t));
01743     if (vol->vol_l2p == NULL) {
01744         free(vol);
01745         return -1;
01746     }
01747     memset(vol->vol_l2p, 0xff, vol->vol_blocks * sizeof(blknum_t));
01748 
01749     memset(min_used, 0xff, sizeof(min_used));
01750 
01751     /*
01752        ** Fill the block translation table.
01753      */
01754     for (b = 0; b < vol->vol_blocks; b++) {
01755         FlashReadBlockHead(vol->vol_ifc, b, &bh);
01756         /* Check if this is a logical block. */
01757         if (bh.bh_logblk < vol->vol_blocks) {
01758             /* Verify the CRC. */
01759             if (FlashCheckBlock(vol->vol_ifc, b)) {
01760                 /* Bad block, remove it. */
01761                 FlashEraseEntry(vol->vol_ifc, b);
01762                 /* Mark the volume fixed. */
01763                 vol->vol_attrib |= UFLASH_VOLF_FIXED;
01764             } else {
01765                 /* Check if we already found another version. */
01766                 if (vol->vol_l2p[bh.bh_logblk] < vol->vol_blocks) {
01767                     BLOCKHEAD bho;
01768 
01769                     /* Read the previous entry. */
01770                     FlashReadBlockHead(vol->vol_ifc, vol->vol_l2p[bh.bh_logblk], &bho);
01771                     /* Compare versions. */
01772                     if (bho.bh_version > bh.bh_version) {
01773                         if (bho.bh_version - bh.bh_version > vol->vol_blocks) {
01774                             /* The current version overflowed. */
01775                             FlashEraseEntry(vol->vol_ifc, b);
01776                         } else {
01777                             FlashEraseEntry(vol->vol_ifc, vol->vol_l2p[bh.bh_logblk]);
01778                             vol->vol_l2p[bh.bh_logblk] = b;
01779                         }
01780                     } else if (bh.bh_version - bho.bh_version < vol->vol_blocks) {
01781                         /* The current version is higher. */
01782                         FlashEraseEntry(vol->vol_ifc, b);
01783                     } else {
01784                         FlashEraseEntry(vol->vol_ifc, vol->vol_l2p[bh.bh_logblk]);
01785                         vol->vol_l2p[bh.bh_logblk] = b;
01786                     }
01787                     /* Mark the volume fixed. */
01788                     vol->vol_attrib |= UFLASH_VOLF_FIXED;
01789                 } else {
01790                     /* First version of this block. */
01791                     vol->vol_l2p[bh.bh_logblk] = b;
01792                 }
01793             }
01794         }
01795     }
01796     /* Initialize the mutex. */
01797     NutEventPost(&vol->vol_mutex);
01798     return 0;
01799 }
01800 
01808 static int UFlashUnmount(NUTDEVICE * dev)
01809 {
01810     UFLASHVOLUME *vol;
01811 
01812     /* Sanity check. */
01813     NUTASSERT(dev != NULL);
01814 
01815     /* Get the volume information structure. */
01816     NUTASSERT(dev->dev_dcb != NULL);
01817     vol = (UFLASHVOLUME *) dev->dev_dcb;
01818 
01819     /* Release allocated heap space. */
01820     NUTASSERT(vol->vol_l2p != NULL);
01821     free(vol->vol_l2p);
01822     free(vol);
01823 
01824     /* Mark the file system driver unmounted. */
01825     dev->dev_dcb = NULL;
01826 
01827     return 0;
01828 }
01829 
01842 int UFlashAttach(NUTDEVICE * dev, NUTSERIALFLASH * sfi, NUTSPIBUS * bus)
01843 {
01844     /* Sanity checks. */
01845     NUTASSERT(dev != NULL);
01846     NUTASSERT(sfi != NULL);
01847     NUTASSERT(sfi->sf_node != NULL);
01848     NUTASSERT(sfi->sf_init != NULL);
01849     NUTASSERT(bus != NULL);
01850     NUTASSERT(bus->bus_initnode != NULL);
01851 
01852     sfi->sf_node->node_bus = bus;
01853     if ((*bus->bus_initnode) (sfi->sf_node)) {
01854         return -1;
01855     }
01856     NutEventPost(&sfi->sf_node->node_bus->bus_mutex);
01857 
01858     if ((*sfi->sf_init) (sfi) == 0) {
01859         dev->dev_icb = (void *) sfi;
01860         if (UFlashMount(dev) == 0) {
01861             return 0;
01862         }
01863         dev->dev_icb = NULL;
01864     }
01865     return -1;
01866 }
01867 
01877 void UFlashDetach(NUTDEVICE * dev)
01878 {
01879     NUTSERIALFLASH *sfi;
01880 
01881     UFlashUnmount(dev);
01882 
01883     /* Release and detach the serial flash interface. */
01884     sfi = (NUTSERIALFLASH *) dev->dev_icb;
01885     NUTASSERT(sfi != NULL);
01886     NUTASSERT(sfi->sf_exit != NULL);
01887     (*sfi->sf_exit) (sfi);
01888     dev->dev_icb = NULL;
01889 }
01890 
01905 int UFlashFormat(NUTDEVICE * dev, NUTSERIALFLASH * sfi, NUTSPIBUS * bus)
01906 {
01907     int rc;
01908     blknum_t n;
01909 
01910     /* Sanity checks. */
01911     NUTASSERT(dev != NULL);
01912     NUTASSERT(sfi != NULL);
01913     NUTASSERT(dev->dev_dcb == NULL);
01914 
01915     sfi->sf_node->node_bus = bus;
01916     if ((*sfi->sf_node->node_bus->bus_initnode) (sfi->sf_node)) {
01917         return -1;
01918     }
01919     NutEventPost(&sfi->sf_node->node_bus->bus_mutex);
01920 
01921     rc = (*sfi->sf_init) (sfi);
01922     if (rc == 0) {
01923         n = (blknum_t) ((sfi->sf_units - sfi->sf_rsvbot - sfi->sf_rsvtop) / UFLASH_BLOCK_UNITS);
01924         if (n > UFLASH_MAX_BLOCKS) {
01925             n = UFLASH_MAX_BLOCKS;
01926         }
01927         FlashEraseBlocks(sfi, n);
01928         (*sfi->sf_exit) (sfi);
01929     }
01930     return 0;
01931 }
01932 
01957 static int UFlashIOCtl(NUTDEVICE * dev, int req, void *conf)
01958 {
01959     int rc = -1;
01960 
01961     switch (req) {
01962     case FS_STATUS:
01963         NUTASSERT(conf != NULL);
01964         {
01965             FSCP_STATUS *par = (FSCP_STATUS *) conf;
01966             rc = UFlashFileStatus(dev, par->par_path, par->par_stp);
01967         }
01968         break;
01969     case FS_DIR_CREATE:
01970         rc = 0;
01971         break;
01972     case FS_DIR_REMOVE:
01973         rc = 0;
01974         break;
01975     case FS_DIR_OPEN:
01976         /* Open a directory for reading entries. */
01977         NUTASSERT(conf != NULL);
01978         {
01979             DIR *dir = (DIR *) conf;
01980 
01981             if ((dir->dd_fd = UFlashDirOpen(dev, dir->dd_buf)) != NUTFILE_EOF) {
01982                 rc = 0;
01983             }
01984         }
01985         break;
01986     case FS_DIR_CLOSE:
01987         NUTASSERT(conf != NULL);
01988         rc = UFlashDirClose(((DIR *) conf)->dd_fd);
01989         break;
01990     case FS_DIR_READ:
01991         rc = UFlashDirRead((DIR *) conf);
01992         break;
01993     case FS_FILE_DELETE:
01994         rc = UFlashFileRemove(dev, (char *) conf);
01995         break;
01996     case FS_FILE_SEEK:
01997         NUTASSERT(conf != NULL);
01998         UFlashFileSeek((NUTFILE *) ((IOCTL_ARG3 *) conf)->arg1, /* */
01999                        (long *) ((IOCTL_ARG3 *) conf)->arg2,    /* */
02000                        (int) ((IOCTL_ARG3 *) conf)->arg3);
02001         break;
02002     case FS_RENAME:
02003         /* Rename an existing file. */
02004         NUTASSERT(conf != NULL);
02005         {
02006             FSCP_RENAME *par = (FSCP_RENAME *) conf;
02007             rc = UFlashFileRename(dev, par->par_old, par->par_new);
02008         }
02009         break;
02010     case FS_VOL_MOUNT:
02011         /* Mount a volume. */
02012         rc = UFlashMount(dev);
02013         break;
02014     case FS_VOL_UNMOUNT:
02015         /* Unmount a volume. */
02016         rc = UFlashUnmount(dev);
02017         break;
02018     }
02019     return rc;
02020 }
02021 
02031 static int UFlashInit(NUTDEVICE * dev)
02032 {
02033     return 0;
02034 }
02035 
02039 NUTDEVICE devUFlash0 = {
02040     0,                          
02041     {'U', 'F', 'L', 'A', 'S', 'H', '0', 0, 0}
02042     ,                           
02043     IFTYP_FS,                   
02044     0,                          
02045     0,                          
02046     NULL,                       
02047     NULL,                       
02048     UFlashInit,                 
02049     UFlashIOCtl,                
02050     UFlashFileRead,             
02051     UFlashFileWrite,            
02052 #ifdef __HARVARD_ARCH__
02053     UFlashFileWrite_P,          
02054 #endif
02055     UFlashFileOpen,             
02056     UFlashFileClose,            
02057     UFlashFileSize              
02058 };
02059 
02063 NUTDEVICE devUFlash1 = {
02064     0,                          
02065     {'U', 'F', 'L', 'A', 'S', 'H', '1', 0, 0}
02066     ,                           
02067     IFTYP_FS,                   
02068     1,                          
02069     0,                          
02070     NULL,                       
02071     NULL,                       
02072     UFlashInit,                 
02073     UFlashIOCtl,                
02074     UFlashFileRead,             
02075     UFlashFileWrite,            
02076 #ifdef __HARVARD_ARCH__
02077     UFlashFileWrite_P,          
02078 #endif
02079     UFlashFileOpen,             
02080     UFlashFileClose,            
02081     UFlashFileSize              
02082 };
02083