123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- /*
- +------------------------------------------------------------------------------
- | 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;
- }
|