mtd块设备缓冲操作---mtdblock.c

来源:互联网 发布:c语言学生成绩管理删除 编辑:程序博客网 时间:2024/05/21 20:30

这个文件中并没有增加mtd块设备,mtd块设备的代码文件是Mtd_blkdevs.c。它的功能是为mtd块设备读写提供缓冲操作。

另外还有一个文件mtdblock_ro.c,它定义的是mtd块设备缓冲的只读操作。

驱动入口:

static struct mtd_blktrans_ops mtdblock_tr = {.name= "mtdblock",.major= 31,.part_bits= 0,.blksize = 512,.open= mtdblock_open,.flush= mtdblock_flush,.release= mtdblock_release,.readsect= mtdblock_readsect,.writesect= mtdblock_writesect,.add_mtd= mtdblock_add_mtd,   //增加一个mtd_blktrans_dev.remove_dev= mtdblock_remove_dev,.owner= THIS_MODULE,};static int __init init_mtdblock(void){return register_mtd_blktrans(&mtdblock_tr);}static void __exit cleanup_mtdblock(void){deregister_mtd_blktrans(&mtdblock_tr);}module_init(init_mtdblock);module_exit(cleanup_mtdblock);


缓冲数据结构定义:

static struct mtdblk_dev {struct mtd_info *mtd;int count;//使用计数struct mutex cache_mutex;unsigned char *cache_data;   //缓冲区数据unsigned long cache_offset;  //缓冲区数据的偏移地址(全局)unsigned int cache_size;     //一般等于FLASH的擦除大小enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state;} *mtdblks[MAX_MTD_DEVICES];


mtd_blktrans_dev结构:

struct mtd_blktrans_dev {struct mtd_blktrans_ops *tr;struct list_head list;struct mtd_info *mtd;struct mutex lock;int devnum; //分区序号,等于mtd->indexunsigned long size;//分区大小,单位是512字节int readonly; //是否是只读的void *blkcore_priv; //指向gen_disk结构};

mtd_blktrans_dev对应于mtd_info,每个分区有一个mtd_blktrans_dev实体。

(1)open例程

static int mtdblock_open(struct mtd_blktrans_dev *mbd){struct mtdblk_dev *mtdblk;struct mtd_info *mtd = mbd->mtd;int dev = mbd->devnum;DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n");if (mtdblks[dev]) {//如果如果mtdblk_dev存在,则返回mtdblks[dev]->count++;return 0;}//mtdblk_dev不存在,则新增一个/* OK, it's not open. Create cache info for it */mtdblk = kzalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);if (!mtdblk)return -ENOMEM;mtdblk->count = 1;mtdblk->mtd = mtd;mutex_init(&mtdblk->cache_mutex);mtdblk->cache_state = STATE_EMPTY;if ( !(mtdblk->mtd->flags & MTD_NO_ERASE) && mtdblk->mtd->erasesize) {mtdblk->cache_size = mtdblk->mtd->erasesize;mtdblk->cache_data = NULL;}mtdblks[dev] = mtdblk;DEBUG(MTD_DEBUG_LEVEL1, "ok\n");return 0;}
(2)release例程
它检查检查mtdblk_dev的使用计数,若为0,则释放内存。
static int mtdblock_release(struct mtd_blktrans_dev *mbd){int dev = mbd->devnum;struct mtdblk_dev *mtdblk = mtdblks[dev];   DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n");mutex_lock(&mtdblk->cache_mutex);write_cached_data(mtdblk);mutex_unlock(&mtdblk->cache_mutex);if (!--mtdblk->count) {/* It was the last usage. Free the device */mtdblks[dev] = NULL;if (mtdblk->mtd->sync)mtdblk->mtd->sync(mtdblk->mtd);vfree(mtdblk->cache_data);kfree(mtdblk);}DEBUG(MTD_DEBUG_LEVEL1, "ok\n");return 0;}


(3)writesect例程

static int mtdblock_writesect(struct mtd_blktrans_dev *dev,      unsigned long block, char *buf){struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];if (unlikely(!mtdblk->cache_data && mtdblk->cache_size)) {//如果mtdblk->cache_data为空,则分配内存mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize);if (!mtdblk->cache_data)return -EINTR;/* -EINTR is not really correct, but it is the best match * documented in man 2 write for all cases.  We could also * return -EAGAIN sometimes, but why bother? */}return do_cached_write(mtdblk, block<<9, 512, buf);//把512字节数据写入到block<<9的地址处}static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,    int len, const char *buf){struct mtd_info *mtd = mtdblk->mtd;unsigned int sect_size = mtdblk->cache_size;size_t retlen;int ret;DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n",mtd->name, pos, len);if (!sect_size) //直接写入return mtd->write(mtd, pos, len, &retlen, buf);///单次写入的数据大小不能超过sect_size,写入时如果小于sect_size,则先写入到cachewhile (len > 0) {unsigned long sect_start = (pos/sect_size)*sect_size;unsigned int offset = pos - sect_start;unsigned int size = sect_size - offset;if( size > len )size = len;if (size == sect_size) {//如果刚好是一个sect的大小,则不经cache直接写入/* * We are covering a whole sector.  Thus there is no * need to bother with the cache while it may still be * useful for other partial writes. */ret = erase_write (mtd, pos, size, buf);if (ret)return ret;} else {//使用cache/* Partial sector: need to use the cache */if (mtdblk->cache_state == STATE_DIRTY &&   //如果cache有数据且cache的数据和写入的数据不在同一个sect中,则先把cache中的数据写入    mtdblk->cache_offset != sect_start) {ret = write_cached_data(mtdblk);if (ret)return ret;}if (mtdblk->cache_state == STATE_EMPTY ||   //如果cache中没有数据,则先把FLASH中对应的数据读出来放到cache    mtdblk->cache_offset != sect_start) {/* fill the cache with the current sector */mtdblk->cache_state = STATE_EMPTY;ret = mtd->read(mtd, sect_start, sect_size,&retlen, mtdblk->cache_data);if (ret)return ret;if (retlen != sect_size)return -EIO;mtdblk->cache_offset = sect_start;mtdblk->cache_size = sect_size;mtdblk->cache_state = STATE_CLEAN;}/* write data to our local cache *///修改cache中的数据memcpy (mtdblk->cache_data + offset, buf, size);mtdblk->cache_state = STATE_DIRTY;}buf += size;pos += size;len -= size;}return 0;}static int write_cached_data (struct mtdblk_dev *mtdblk){struct mtd_info *mtd = mtdblk->mtd;int ret;if (mtdblk->cache_state != STATE_DIRTY)return 0;DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: writing cached data for \"%s\" ""at 0x%lx, size 0x%x\n", mtd->name,mtdblk->cache_offset, mtdblk->cache_size);//erase_write调用mtd_info的相应操作ret = erase_write (mtd, mtdblk->cache_offset,   mtdblk->cache_size, mtdblk->cache_data);if (ret)return ret;/* * Here we could argubly set the cache state to STATE_CLEAN. * However this could lead to inconsistency since we will not * be notified if this content is altered on the flash by other * means.  Let's declare it empty and leave buffering tasks to * the buffer cache instead. */mtdblk->cache_state = STATE_EMPTY;return 0;}


(3)readsect例程

static int mtdblock_readsect(struct mtd_blktrans_dev *dev,      unsigned long block, char *buf){struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];return do_cached_read(mtdblk, block<<9, 512, buf);}static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos,   int len, char *buf){struct mtd_info *mtd = mtdblk->mtd;unsigned int sect_size = mtdblk->cache_size;size_t retlen;int ret;DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n",mtd->name, pos, len);if (!sect_size)return mtd->read(mtd, pos, len, &retlen, buf);while (len > 0) {unsigned long sect_start = (pos/sect_size)*sect_size;unsigned int offset = pos - sect_start;unsigned int size = sect_size - offset;if (size > len)size = len;/* * Check if the requested data is already cached 检查读取的数据是否已经在cache中 * Read the requested amount of data from our internal cache if it * contains what we want, otherwise we read the data directly * from flash. */if (mtdblk->cache_state != STATE_EMPTY &&    mtdblk->cache_offset == sect_start) {memcpy (buf, mtdblk->cache_data + offset, size);} else {ret = mtd->read(mtd, pos, size, &retlen, buf);if (ret)return ret;if (retlen != size)return -EIO;}buf += size;pos += size;len -= size;}return 0;}

(4)flush例程

它将cache中数据写入到存储

static int mtdblock_flush(struct mtd_blktrans_dev *dev){struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];mutex_lock(&mtdblk->cache_mutex);write_cached_data(mtdblk);mutex_unlock(&mtdblk->cache_mutex);if (mtdblk->mtd->sync)mtdblk->mtd->sync(mtdblk->mtd);return 0;}



 

0 0
原创粉丝点击