Add support for devices which can partial write a block.
authorbatt <batt@38d2e660-2303-0410-9eaa-f027e97ec537>
Fri, 30 Jul 2010 15:10:43 +0000 (15:10 +0000)
committerbatt <batt@38d2e660-2303-0410-9eaa-f027e97ec537>
Fri, 30 Jul 2010 15:10:43 +0000 (15:10 +0000)
Update drivers accordingly.

git-svn-id: https://src.develer.com/svnoss/bertos/trunk@4108 38d2e660-2303-0410-9eaa-f027e97ec537

bertos/drv/sd.c
bertos/fs/battfs.c
bertos/io/kblock.c
bertos/io/kblock.h
bertos/io/kblock_file.c
bertos/io/kblock_ram.c

index 2b462b7b4734ba8a800010c7ee005f841ba5ef73..091a42bde073e3338ca2b15a65579a67c8b9e28f 100644 (file)
@@ -278,10 +278,12 @@ static size_t sd_readDirect(struct KBlock *b, block_idx_t idx, void *buf, size_t
 #define SD_WRITE_SINGLEBLOCK 0x58
 #define SD_DATA_ACCEPTED     0x05
 
-static int sd_writeBlock(KBlock *b, block_idx_t idx, const void *buf)
+static size_t sd_writeDirect(KBlock *b, block_idx_t idx, const void *buf, size_t offset, size_t size)
 {
        Sd *sd = SD_CAST(b);
        KFile *fd = sd->ch;
+       ASSERT(offset == 0);
+       ASSERT(size == SD_DEFAULT_BLOCKLEN);
 
        LOG_INFO("writing block %ld\n", idx);
        if (sd->tranfer_len != SD_DEFAULT_BLOCKLEN)
@@ -289,7 +291,7 @@ static int sd_writeBlock(KBlock *b, block_idx_t idx, const void *buf)
                if ((sd->r1 = sd_setBlockLen(sd, SD_DEFAULT_BLOCKLEN)))
                {
                        LOG_ERR("setBlockLen failed: %04X\n", sd->r1);
-                       return sd->r1;
+                       return 0;
                }
                sd->tranfer_len = SD_DEFAULT_BLOCKLEN;
        }
@@ -302,7 +304,7 @@ static int sd_writeBlock(KBlock *b, block_idx_t idx, const void *buf)
        {
                LOG_ERR("write single block failed: %04X\n", sd->r1);
                sd_select(sd, false);
-               return sd->r1;
+               return 0;
        }
 
        kfile_putc(SD_STARTTOKEN, fd);
@@ -320,7 +322,7 @@ static int sd_writeBlock(KBlock *b, block_idx_t idx, const void *buf)
                return EOF;
        }
 
-       return 0;
+       return SD_DEFAULT_BLOCKLEN;
 }
 
 void sd_writeTest(Sd *sd)
@@ -330,7 +332,7 @@ void sd_writeTest(Sd *sd)
 
        for (block_idx_t i = 0; i < sd->b.blk_cnt; i++)
        {
-               LOG_INFO("writing block %ld: %s\n", i, (sd_writeBlock(&sd->b, i, buf) == 0) ? "OK" : "FAIL");
+               LOG_INFO("writing block %ld: %s\n", i, (sd_writeDirect(&sd->b, i, buf, 0, SD_DEFAULT_BLOCKLEN) == SD_DEFAULT_BLOCKLEN) ? "OK" : "FAIL");
        }
 }
 
@@ -351,7 +353,7 @@ bool sd_test(Sd *sd)
                        kputchar('\n');
        }
 
-       if (sd_writeBlock(&sd->b, 0, buf) != 0)
+       if (sd_writeDirect(&sd->b, 0, buf, 0, SD_DEFAULT_BLOCKLEN) != SD_DEFAULT_BLOCKLEN)
                return false;
 
        memset(buf, 0, sizeof(buf));
@@ -386,7 +388,7 @@ static int sd_clearerr(KBlock *b)
 static const KBlockVTable sd_unbuffered_vt =
 {
        .readDirect = sd_readDirect,
-       .writeBlock = sd_writeBlock,
+       .writeDirect = sd_writeDirect,
 
        .error = sd_error,
        .clearerr = sd_clearerr,
@@ -395,7 +397,7 @@ static const KBlockVTable sd_unbuffered_vt =
 static const KBlockVTable sd_buffered_vt =
 {
        .readDirect = sd_readDirect,
-       .writeBlock = sd_writeBlock,
+       .writeDirect = sd_writeDirect,
 
        .readBuf = kblock_swReadBuf,
        .writeBuf = kblock_swWriteBuf,
@@ -517,7 +519,7 @@ bool sd_initBuf(Sd *sd, KFile *ch)
        if (sd_blockInit(sd, ch))
        {
                sd->b.priv.buf = sd_buf;
-               sd->b.priv.flags |= KB_BUFFERED;
+               sd->b.priv.flags |= KB_BUFFERED | KB_PARTIAL_WRITE;
                sd->b.priv.vt = &sd_buffered_vt;
                sd->b.priv.vt->load(&sd->b, 0);
                return true;
index 4877fc623f078c58c9dc271cd7d54c8072e8e9df..f40d310d8d3bae3d77f500dbd6640f30b9054700 100644 (file)
@@ -366,7 +366,7 @@ bool battfs_mount(struct BattFsSuper *disk, struct KBlock *dev, pgcnt_t *page_ar
        pgoff_t filelen_table[BATTFS_MAX_FILES];
 
        ASSERT(dev);
-       ASSERT(kblock_buffered(dev));
+       ASSERT(kblock_partialWrite(dev));
        disk->dev = dev;
 
        ASSERT(disk->dev->blk_size > BATTFS_HEADER_LEN);
@@ -591,11 +591,12 @@ static size_t battfs_write(struct KFile *fd, const void *_buf, size_t size)
 
                /*
                 * Renew page only if is not in cache.
-                * This avoids rewriting the same page continuously 
+                * This avoids rewriting the same page continuously
                 * if the user code keeps writing in the same portion
                 * of the file.
                 */
-               if ((fdb->start[fdb->max_off] != kblock_cachedBlock(disk->dev)) || !kblock_cacheDirty(disk->dev))
+               if (kblock_buffered(disk->dev)
+                       && ((fdb->start[fdb->max_off] != kblock_cachedBlock(disk->dev)) || !kblock_cacheDirty(disk->dev)))
                {
                        new_page = renewPage(disk, fdb->start[fdb->max_off]);
                        if (new_page == NO_SPACE)
@@ -709,7 +710,8 @@ static size_t battfs_write(struct KFile *fd, const void *_buf, size_t size)
                        }
 
                        /* Renew page only if is not in cache. */
-                       if ((fdb->start[fdb->max_off] != kblock_cachedBlock(disk->dev)) || !kblock_cacheDirty(disk->dev))
+                       if (kblock_buffered(disk->dev)
+                               && ((fdb->start[fdb->max_off] != kblock_cachedBlock(disk->dev)) || !kblock_cacheDirty(disk->dev)))
                        {
                                new_page = renewPage(disk, fdb->start[pg_offset]);
                                if (new_page == NO_SPACE)
@@ -731,7 +733,7 @@ static size_t battfs_write(struct KFile *fd, const void *_buf, size_t size)
                                LOG_INFO("Using cached block %d\n", fdb->start[pg_offset]);
                                new_page = fdb->start[pg_offset];
                        }
-                               
+
                        curr_hdr.seq++;
                }
                //LOG_INFO("writing to buffer for page %d, offset %d, size %d\n", disk->curr_page, addr_offset, wr_len);
index 7355deeded97884c6c010decd54a54f7580d8a83..69b5b159eba3ce711e0ccfd89a1067c059c39207 100644 (file)
@@ -51,11 +51,11 @@ INLINE size_t kblock_readDirect(struct KBlock *b, block_idx_t index, void *buf,
        return b->priv.vt->readDirect(b, b->priv.blk_start + index, buf, offset, size);
 }
 
-INLINE int kblock_writeBlock(struct KBlock *b, block_idx_t index, const void *buf)
+INLINE size_t kblock_writeDirect(struct KBlock *b, block_idx_t index, const void *buf, size_t offset, size_t size)
 {
-       KB_ASSERT_METHOD(b, writeBlock);
+       KB_ASSERT_METHOD(b, writeDirect);
        ASSERT(index < b->blk_cnt);
-       return b->priv.vt->writeBlock(b, b->priv.blk_start + index, buf);
+       return b->priv.vt->writeDirect(b, b->priv.blk_start + index, buf, offset, size);
 }
 
 INLINE size_t kblock_readBuf(struct KBlock *b, void *buf, size_t offset, size_t size)
@@ -169,9 +169,11 @@ size_t kblock_write(struct KBlock *b, block_idx_t idx, const void *buf, size_t o
        }
        else
        {
-               ASSERT(offset == 0);
-               ASSERT(size == b->blk_size);
-               return (kblock_writeBlock(b, idx, buf) == 0) ? size : 0;
+               #ifdef _DEBUG
+               if (offset != 0 || size != b->blk_size)
+                       ASSERT(kblock_partialWrite(b));
+               #endif
+               return kblock_writeDirect(b, idx, buf, offset, size);
        }
 }
 
@@ -180,14 +182,40 @@ int kblock_copy(struct KBlock *b, block_idx_t src, block_idx_t dest)
        ASSERT(b);
        ASSERT(src < b->blk_cnt);
        ASSERT(dest < b->blk_cnt);
-       ASSERT(kblock_buffered(b));
 
-       if (!kblock_loadPage(b, src))
-               return EOF;
+       if (kblock_buffered(b))
+       {
+               if (!kblock_loadPage(b, src))
+                       return EOF;
 
-       b->priv.curr_blk = dest;
-       kblock_setDirty(b, true);
-       return 0;
+               b->priv.curr_blk = dest;
+               kblock_setDirty(b, true);
+               return 0;
+       }
+       else if (kblock_partialWrite(b))
+       {
+               uint8_t buf[16];
+               size_t blk_size = b->blk_size;
+               size_t offset = 0;
+
+               while (blk_size)
+               {
+                       size_t size = MIN(sizeof(buf), blk_size);
+                       if (kblock_readDirect(b, src, buf, offset, size) != size)
+                               return EOF;
+                       if (kblock_writeDirect(b, dest, buf, offset, size) != size)
+                               return EOF;
+
+                       blk_size -= size;
+                       offset += size;
+               }
+               return 0;
+       }
+       else
+       {
+               ASSERT(0);
+               return EOF;
+       }
 }
 
 int kblock_swLoad(struct KBlock *b, block_idx_t index)
@@ -197,7 +225,7 @@ int kblock_swLoad(struct KBlock *b, block_idx_t index)
 
 int kblock_swStore(struct KBlock *b, block_idx_t index)
 {
-       return kblock_writeBlock(b, index, b->priv.buf);
+       return (kblock_writeDirect(b, index, b->priv.buf, 0, b->blk_size) == b->blk_size) ? 0 : EOF;
 }
 
 size_t kblock_swReadBuf(struct KBlock *b, void *buf, size_t offset, size_t size)
index 99135ab24801de6da2849f191a58b4514733953a..7775d7b87f14f9f28df7c014b89f6f3e15fb2bda 100644 (file)
@@ -57,8 +57,8 @@ struct KBlock;
  *
  *  \{
  */
-typedef size_t (* kblock_read_direct_t) (struct KBlock *b, block_idx_t index, void *buf, size_t offset, size_t size);
-typedef int    (* kblock_write_block_t) (struct KBlock *b, block_idx_t index, const void *buf);
+typedef size_t (* kblock_read_direct_t)  (struct KBlock *b, block_idx_t index, void *buf, size_t offset, size_t size);
+typedef size_t (* kblock_write_direct_t) (struct KBlock *b, block_idx_t index, const void *buf, size_t offset, size_t size);
 
 typedef size_t (* kblock_read_t)        (struct KBlock *b, void *buf, size_t offset, size_t size);
 typedef size_t (* kblock_write_t)       (struct KBlock *b, const void *buf, size_t offset, size_t size);
@@ -76,7 +76,7 @@ typedef int    (* kblock_close_t)       (struct KBlock *b);
 typedef struct KBlockVTable
 {
        kblock_read_direct_t readDirect;
-       kblock_write_block_t writeBlock;
+       kblock_write_direct_t writeDirect;
 
        kblock_read_t  readBuf;
        kblock_write_t writeBuf;
@@ -92,6 +92,7 @@ typedef struct KBlockVTable
 
 #define KB_BUFFERED    BV(0) ///< Internal flag: true if the KBlock has a buffer
 #define KB_CACHE_DIRTY BV(1) ///< Internal flag: true if the cache is dirty
+#define KB_PARTIAL_WRITE BV(2) ///< Internal flag: true if the device allows partial block write
 
 /**
  * KBlock private members.
@@ -264,6 +265,18 @@ INLINE bool kblock_cacheDirty(struct KBlock *b)
        return kblock_buffered(b) && (b->priv.flags & KB_CACHE_DIRTY);
 }
 
+/**
+ * \return true if the device \a b supports partial block write. That is, you
+ *         can call kblock_write() with a size which is lesser than the block
+ *         size.
+ * \param b KBlock device.
+ * \sa kblock_write().
+ */
+INLINE bool kblock_partialWrite(struct KBlock *b)
+{
+       ASSERT(b);
+       return (b->priv.flags & KB_PARTIAL_WRITE);
+}
 
 /**
  * Read data from the block device.
@@ -297,9 +310,9 @@ size_t kblock_read(struct KBlock *b, block_idx_t idx, void *buf, size_t offset,
  * This function will write \a size bytes to block \a idx starting at
  * address \a offset inside the block.
  *
- * \note Partial block writes are supported only if the device is opened in
- *       buffered mode. You can use kblock_buffered() to check if the device
- *       has an internal cache or not.
+ * \note Partial block writes are supported only on certain devices.
+ *       You can use kblock_partialWrite() in order to check if the device
+ *       has this feature or not.
  *
  * \note If the device is opened in buffered mode, this function will use
  *       efficiently and trasparently the cache provided.
@@ -314,7 +327,7 @@ size_t kblock_read(struct KBlock *b, block_idx_t idx, void *buf, size_t offset,
  *
  * \return the number of bytes written.
  *
- * \sa kblock_read(), kblock_flush(), kblock_buffered().
+ * \sa kblock_read(), kblock_flush(), kblock_buffered(), kblock_partialWrite().
  */
 size_t kblock_write(struct KBlock *b, block_idx_t idx, const void *buf, size_t offset, size_t size);
 
@@ -336,7 +349,8 @@ int kblock_flush(struct KBlock *b);
  *
  * This function will copy the content of block \a src to block \a dest.
  *
- * \note This function is available only on devices opened in buffered mode.
+ * \note This function is available only on devices which support partial
+ *       block write or are opened in buffered mode.
  *
  * \param b KBlock device.
  * \param src source block number.
index ae680815ade31890bcd18693a2f3bf405819e18a..cd18431d101c6b141804d0651a721d2f05efa7b2 100644 (file)
@@ -79,13 +79,13 @@ static size_t kblockfile_writeBuf(struct KBlock *b, const void *buf, size_t offs
        return size;
 }
 
-static int kblockfile_writeBlock(struct KBlock *b, block_idx_t index, const void *buf)
+static size_t kblockfile_writeDirect(struct KBlock *b, block_idx_t index, const void *buf, size_t offset, size_t size)
 {
        KBlockFile *f = KBLOCKFILE_CAST(b);
        ASSERT(buf);
        ASSERT(index < b->blk_cnt);
-       fseek(f->fp, index * b->blk_size, SEEK_SET);
-       return (fwrite(f->b.priv.buf, 1, b->blk_size, f->fp) == b->blk_size) ? 0 : EOF;
+       fseek(f->fp, index * b->blk_size + offset, SEEK_SET);
+       return fwrite(buf, 1, size, f->fp);
 }
 
 static int kblockfile_error(struct KBlock *b)
@@ -119,7 +119,7 @@ static const KBlockVTable kblockfile_hwbuffered_vt =
        .writeBuf = kblockfile_writeBuf,
        .load = kblockfile_load,
        .store = kblockfile_store,
-       
+
        .error = kblockfile_error,
        .clearerr = kblockfile_claererr,
        .close = kblockfile_close,
@@ -128,13 +128,13 @@ static const KBlockVTable kblockfile_hwbuffered_vt =
 static const KBlockVTable kblockfile_swbuffered_vt =
 {
        .readDirect = kblockfile_readDirect,
-       .writeBlock =kblockfile_writeBlock,
-       
+       .writeDirect =kblockfile_writeDirect,
+
        .readBuf = kblock_swReadBuf,
        .writeBuf = kblock_swWriteBuf,
        .load = kblock_swLoad,
        .store = kblock_swStore,
-       
+
        .error = kblockfile_error,
        .clearerr = kblockfile_claererr,
        .close = kblockfile_close,
@@ -143,7 +143,7 @@ static const KBlockVTable kblockfile_swbuffered_vt =
 static const KBlockVTable kblockfile_unbuffered_vt =
 {
        .readDirect = kblockfile_readDirect,
-       .writeBlock =kblockfile_writeBlock,
+       .writeDirect =kblockfile_writeDirect,
 
        .error = kblockfile_error,
        .clearerr = kblockfile_claererr,
@@ -165,7 +165,8 @@ void kblockfile_init(KBlockFile *f, FILE *fp, bool hwbuf, void *buf, size_t bloc
        f->fp = fp;
        f->b.blk_size = block_size;
        f->b.blk_cnt = block_count;
-       
+
+       f->b.priv.flags |= KB_PARTIAL_WRITE;
        if (buf)
        {
                f->b.priv.flags |= KB_BUFFERED;
index eff9675f721d30f9f34f61537518e21b36d68cfb..e3780d7d92777a7b8fc3ba2aab7c6223e2d6c8d9 100644 (file)
@@ -75,14 +75,14 @@ static size_t kblockram_writeBuf(struct KBlock *b, const void *buf, size_t offse
        return size;
 }
 
-static int kblockram_writeBlock(struct KBlock *b, block_idx_t index, const void *buf)
+static size_t kblockram_writeDirect(struct KBlock *b, block_idx_t index, const void *buf, size_t offset, size_t size)
 {
        KBlockRam *r = KBLOCKRAM_CAST(b);
        ASSERT(buf);
        ASSERT(index < b->blk_cnt);
 
-       memcpy(r->membuf + index * r->b.blk_size, buf, r->b.blk_size);
-       return 0;
+       memcpy(r->membuf + index * r->b.blk_size + offset, buf, size);
+       return size;
 }
 
 static int kblockram_dummy(UNUSED_ARG(struct KBlock *,b))
@@ -93,12 +93,12 @@ static int kblockram_dummy(UNUSED_ARG(struct KBlock *,b))
 static const KBlockVTable kblockram_hwbuffered_vt =
 {
        .readDirect = kblockram_readDirect,
-       
+
        .readBuf = kblockram_readBuf,
        .writeBuf = kblockram_writeBuf,
        .load = kblockram_load,
        .store = kblockram_store,
-       
+
        .error = kblockram_dummy,
        .clearerr = kblockram_dummy,
        .close = kblockram_dummy,
@@ -108,13 +108,13 @@ static const KBlockVTable kblockram_hwbuffered_vt =
 static const KBlockVTable kblockram_swbuffered_vt =
 {
        .readDirect = kblockram_readDirect,
-       .writeBlock = kblockram_writeBlock,
-       
+       .writeDirect = kblockram_writeDirect,
+
        .readBuf = kblock_swReadBuf,
        .writeBuf = kblock_swWriteBuf,
        .load = kblock_swLoad,
        .store = kblock_swStore,
-               
+
        .error = kblockram_dummy,
        .clearerr = kblockram_dummy,
        .close = kblockram_dummy,
@@ -123,7 +123,7 @@ static const KBlockVTable kblockram_swbuffered_vt =
 static const KBlockVTable kblockram_unbuffered_vt =
 {
        .readDirect = kblockram_readDirect,
-       .writeBlock = kblockram_writeBlock,
+       .writeDirect = kblockram_writeDirect,
 
        .error = kblockram_dummy,
        .clearerr = kblockram_dummy,
@@ -140,7 +140,8 @@ void kblockram_init(KBlockRam *ram, void *buf, size_t size, size_t block_size, b
 
        DB(ram->b.priv.type = KBT_KBLOCKRAM);
        ram->b.blk_size = block_size;
-       
+       ram->b.priv.flags |= KB_PARTIAL_WRITE;
+
        if (buffered)
        {
                ram->b.priv.flags |= KB_BUFFERED;
@@ -148,12 +149,12 @@ void kblockram_init(KBlockRam *ram, void *buf, size_t size, size_t block_size, b
                ram->b.priv.buf = buf;
                // First page used as page buffer
                ram->membuf = (uint8_t *)buf + block_size;
-                       
+
                if (hwbuffered)
                        ram->b.priv.vt = &kblockram_hwbuffered_vt;
                else
                        ram->b.priv.vt = &kblockram_swbuffered_vt;
-               
+
                kblockram_load(&ram->b, 0);
        }
        else