diff options
| author | bernard.xiong <[email protected]> | 2009-07-02 22:48:23 +0000 |
|---|---|---|
| committer | bernard.xiong <[email protected]> | 2009-07-02 22:48:23 +0000 |
| commit | bda4730a9482c23083006abea939ee8d95d6ecff (patch) | |
| tree | 83005121824bd50ac74e63688c0d5eac148665f8 /filesystem/dfs/src/dfs_cache.c | |
| parent | 80c72e66de0b00b1a6de3e3508366a4c3eee458d (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.c | 273 |
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; +} |
