summaryrefslogtreecommitdiff
path: root/filesystem/dfs/src/dfs_cache.c
diff options
context:
space:
mode:
authorbernard.xiong <[email protected]>2009-07-02 22:48:23 +0000
committerbernard.xiong <[email protected]>2009-07-02 22:48:23 +0000
commitbda4730a9482c23083006abea939ee8d95d6ecff (patch)
tree83005121824bd50ac74e63688c0d5eac148665f8 /filesystem/dfs/src/dfs_cache.c
parent80c72e66de0b00b1a6de3e3508366a4c3eee458d (diff)
import RT-Thread RTOS 0.3.x to Google SVN
git-svn-id: https://rt-thread.googlecode.com/svn/trunk@2 bbd45198-f89e-11dd-88c7-29a3b14d5316
Diffstat (limited to 'filesystem/dfs/src/dfs_cache.c')
-rw-r--r--filesystem/dfs/src/dfs_cache.c273
1 files changed, 273 insertions, 0 deletions
diff --git a/filesystem/dfs/src/dfs_cache.c b/filesystem/dfs/src/dfs_cache.c
new file mode 100644
index 0000000000..cd4deab415
--- /dev/null
+++ b/filesystem/dfs/src/dfs_cache.c
@@ -0,0 +1,273 @@
+/*
++------------------------------------------------------------------------------
+| Project : Device Filesystem
++------------------------------------------------------------------------------
+| Copyright 2004 - 2009 www.rt-thread.org
+| All rights reserved.
+|------------------------------------------------------------------------------
+| File : dfs_cache.c, the LUT disk cache implementation
+|------------------------------------------------------------------------------
+| Chang Logs:
+| Date Author Notes
+| 2009-04-26 bernard The first version.
++------------------------------------------------------------------------------
+*/
+#include "dfs_cache.h"
+
+#define ioman_isReqRo(mode) ((mode)&(IOM_MODE_READONLY))
+#define ioman_isReqRw(mode) ((mode)&(IOM_MODE_READWRITE))
+#define ioman_isReqExp(mode) ((mode)&(IOM_MODE_EXP_REQ))
+
+rt_err_t ioman_init(IOManager* ioman)
+{
+ register rt_uint32_t index;
+ RT_ASSERT(ioman != RT_NULL);
+
+ ioman->numbuf = DFS_CACHE_MAX_NUM;
+
+ rt_memset(ioman->sector, 0,sizeof(ioman->sector));
+ rt_memset(ioman->status, 0,sizeof(ioman->status));
+ rt_memset(ioman->usage, 0, sizeof(ioman->usage));
+ rt_memset(ioman->ring_fifo, 0, sizeof(ioman->ring_fifo));
+ rt_memset(ioman->cache, 0, sizeof(ioman->cache));
+
+ /* init fifo */
+ for (index = 0; index < ioman->numbuf; index ++)
+ {
+ ioman->ring_fifo[index] = ioman->numbuf - index - 1;
+ }
+
+ return RT_EOK;
+}
+
+/*
+ * get the last fifo item and put it to the top of fifo ring
+ */
+static rt_uint8_t ioman_ring_fifo_swap(IOManager *ioman)
+{
+ rt_uint8_t bp;
+ rt_uint32_t index;
+
+ bp = ioman->ring_fifo[ioman->numbuf - 1];
+ for (index = ioman->numbuf - 1; index > 0; index --)
+ {
+ ioman->ring_fifo[index] = ioman->ring_fifo[index - 1];
+ }
+
+ ioman->ring_fifo[0] = bp;
+
+ return bp;
+}
+
+/*
+ * get the index of bp in fifo ring and then put it to the top of
+ * fifo ring
+ */
+static void ioman_ring_fifo_relocate(IOManager *ioman, rt_uint32_t bp)
+{
+ rt_uint32_t bp_index = 0;
+ register rt_uint32_t index;
+
+ /* find bp in fifo ring */
+ for (index = 0; index < ioman->numbuf; index ++)
+ {
+ if (ioman->ring_fifo[index] == bp)
+ {
+ bp_index = index;
+ break;
+ }
+ }
+
+ /* not found bp in fifo ring */
+ if (index == ioman->numbuf) return;
+
+ /* move the bp to the top of fifo ring */
+ for (index = bp_index; index > 0; index --)
+ {
+ ioman->ring_fifo[index] = ioman->ring_fifo[index - 1];
+ }
+ ioman->ring_fifo[0] = bp;
+}
+
+/*
+ * get last bp in fifo ring
+ */
+rt_inline rt_uint8_t ioman_ring_fifo_last(IOManager *ioman)
+{
+ RT_ASSERT(ioman != RT_NULL);
+ return ioman->ring_fifo[ioman->numbuf - 1];
+}
+
+static rt_err_t ioman_readSector(IOManager *ioman, rt_uint32_t address, rt_uint8_t* buf)
+{
+ rt_err_t result;
+
+ RT_ASSERT(buf != RT_NULL);
+
+ result = rt_device_read(ioman->device, address * DFS_SECTOR_SIZE, buf, DFS_SECTOR_SIZE);
+ if (result == DFS_SECTOR_SIZE) return RT_EOK;
+
+ return -RT_ERROR;
+}
+
+static rt_err_t ioman_writeSector(IOManager *ioman, rt_uint32_t address, rt_uint8_t* buf)
+{
+ rt_err_t result;
+
+ RT_ASSERT(buf != RT_NULL);
+
+ result = rt_device_write(ioman->device, address * DFS_SECTOR_SIZE, buf, DFS_SECTOR_SIZE);
+ if (result == DFS_SECTOR_SIZE) return RT_EOK;
+
+ return -RT_ERROR;
+}
+
+static rt_int32_t ioman_findSectorInCache(IOManager *ioman, rt_uint32_t address)
+{
+ rt_uint32_t c;
+
+ for(c=0;c<ioman->numbuf;c++)
+ {
+ if((ioman->status[c] & (1 << IOMAN_STATUS_ATTR_VALIDDATA)) &&
+ ioman->sector[c] == address)
+ return (c);
+ }
+
+ return -RT_ERROR;
+}
+
+static rt_err_t ioman_flushSector(IOManager *ioman, rt_uint32_t bp)
+{
+ rt_err_t result;
+
+ RT_ASSERT(ioman != RT_NULL);
+
+ result = ioman_writeSector(ioman, ioman->sector[bp], &ioman->cache[bp][0]);
+ if (result == RT_EOK)
+ {
+ /* set status */
+ ioman->status[bp] &= ~(1 << IOMAN_STATUS_ATTR_WRITE);
+ }
+
+ return result;
+}
+
+rt_uint8_t* ioman_getSector(IOManager *ioman, rt_uint32_t address, rt_uint8_t mode)
+{
+ rt_int32_t bp;
+
+ RT_ASSERT(ioman != RT_NULL);
+
+ bp = ioman_findSectorInCache(ioman, address);
+ if (bp != -RT_ERROR)
+ {
+ /* incress cache usage */
+ ioman->usage[bp] ++;
+
+ /* relocate bp in fifo ring */
+ ioman_ring_fifo_relocate(ioman, bp);
+
+ if (ioman_isReqRw(mode))
+ ioman->status[bp] |= (1 << IOMAN_STATUS_ATTR_WRITE);
+
+ return &(ioman->cache[bp][0]);
+ }
+
+ /* not find in cache, get the last bp in fifo ring */
+ bp = ioman_ring_fifo_last(ioman);
+ if ((ioman->status[bp] & (1 << IOMAN_STATUS_ATTR_WRITE)) &&
+ ioman->usage[bp] == 0)
+ {
+ /* it's a writable buffer, flush it */
+ ioman_flushSector(ioman, bp);
+ }
+
+ /* strip last bp in fifo ring */
+ bp = ioman_ring_fifo_swap(ioman);
+
+ /* read sector */
+ ioman_readSector(ioman, address, &ioman->cache[bp][0]);
+ ioman->sector[bp] = address;
+ ioman->usage [bp] = 1;
+ ioman->status[bp] = (1 << IOMAN_STATUS_ATTR_VALIDDATA);
+ if (ioman_isReqRw(mode))
+ ioman->status[bp] |= (1 << IOMAN_STATUS_ATTR_WRITE);
+
+ return &ioman->cache[bp][0];
+}
+
+rt_err_t ioman_releaseSector(IOManager *ioman, rt_uint8_t* buf)
+{
+ rt_uint32_t bp;
+
+ /* get buffer place */
+ bp = ((rt_uint32_t)buf - (rt_uint32_t)&ioman->cache[0]) / DFS_SECTOR_SIZE;
+
+ /* decrease usage */
+ if (ioman->usage[bp] > 0) ioman->usage[bp] --;
+ if (ioman->usage[bp] == 0)
+ {
+ if(ioman->status[bp] & (1 << IOMAN_STATUS_ATTR_WRITE))
+ {
+ ioman_flushSector(ioman,bp);
+ }
+ }
+
+ return RT_EOK;
+}
+
+rt_err_t ioman_flushRange(IOManager *ioman, rt_uint32_t address_low, rt_uint32_t address_high)
+{
+ rt_uint32_t c;
+
+ if(address_low > address_high)
+ {
+ c = address_low; address_low = address_high; address_high = c;
+ }
+
+ for(c = 0; c < ioman->numbuf; c++)
+ {
+ if((ioman->sector[c]>=address_low)
+ && (ioman->sector[c]<=address_high)
+ && (ioman->status[c] & (1 << IOMAN_STATUS_ATTR_WRITE)))
+ {
+ if(ioman_flushSector(ioman,c) != RT_EOK)
+ return -RT_ERROR;
+
+ /* remove writable status */
+ if(ioman->usage[c]==0) ioman->status[c] &= ~IOMAN_STATUS_ATTR_WRITE;
+ }
+ }
+
+ return RT_EOK;
+}
+
+/*
+ * read multi-sectors directly (none-cachable)
+ */
+rt_err_t ioman_directSectorRead(IOManager *ioman, rt_uint32_t address, rt_uint8_t* buf, rt_uint32_t numsector)
+{
+ rt_err_t result;
+
+ RT_ASSERT(buf != RT_NULL);
+
+ result = rt_device_read(ioman->device, address * DFS_SECTOR_SIZE, buf, DFS_SECTOR_SIZE * numsector);
+ if (result == DFS_SECTOR_SIZE * numsector) return RT_EOK;
+
+ return -RT_ERROR;
+}
+
+/*
+ * write multi-sectors directly (none-cachable)
+ */
+rt_err_t ioman_directSectorWrite(IOManager *ioman, rt_uint32_t address, rt_uint8_t* buf, rt_uint32_t numsector)
+{
+ rt_err_t result;
+
+ RT_ASSERT(buf != RT_NULL);
+
+ result = rt_device_write(ioman->device, address * DFS_SECTOR_SIZE, buf, DFS_SECTOR_SIZE * numsector);
+ if (result == DFS_SECTOR_SIZE * numsector) return RT_EOK;
+
+ return -RT_ERROR;
+}