274 lines
6.9 KiB
C
274 lines
6.9 KiB
C
|
/*
|
||
|
+------------------------------------------------------------------------------
|
||
|
| 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;
|
||
|
}
|