if (mtdblk->cache_state != STATE_DIRTY) return 0;
ret = erase_write (mtd, mtdblk->cache_offset, mtdblk->cache_size, mtdblk->cache_data);
if (ret)
return ret;
mtdblk->cache_state = STATE_EMPTY; return 0; }
函数erase_write写一扇区数据到设备中,写的方法是:先擦除对应扇区,擦除完成后,再写数据。函数erase_write分析如下:
static int erase_write (struct mtd_info *mtd, unsigned long pos, int len, const char *buf) {
struct erase_info erase;
DECLARE_WAITQUEUE(wait, current); wait_queue_head_t wait_q; size_t retlen; int ret;
//首先,擦除flash闪存块
init_waitqueue_head(&wait_q); erase.mtd = mtd;
erase.callback = erase_callback; erase.addr = pos; erase.len = len;
erase.priv = (u_long)&wait_q;
set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&wait_q, &wait);
ret = MTD_ERASE(mtd, &erase); if (ret) {//如果擦除完成
set_current_state(TASK_RUNNING);//运行当前进程 remove_wait_queue(&wait_q, &wait);//清除等待队列 return ret; }
schedule(); //调度来等待擦除工作的完成
remove_wait_queue(&wait_q, &wait); //清除等待队列 //第二步,写数据到flash设备 ret = MTD_WRITE (mtd, pos, len, &retlen, buf);
if (ret)
return ret; if (retlen != len) return -EIO; return 0; }
函数mtdblock_readsect调用了函数do_cached_read,从flash设备中读数据到指定位置的buf中,如果数据在设备的缓存中,就直接从缓存中拷贝到buf中,如果不在,就从flash中读出到buf中。函数do_cached_read说明如下: static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos, int len, char *buf)
其中参数mtdblk是指定的MTD块设备,pos是MTD设备中指定的位置,len是长度,buf是被写入的地址,调用成功时返回0,失败时返回错误码。函数从指定的MTD块设备中缓冲读到指定位置buf中。
MTD核心初始化
MTD核心主要工作是进行电源管理及在/proc文件系统中输出MTD设备的信息。函数init_mtd初始化proc文件系统函数、注册电源管理函数、初始化mtd设备函数,清除模块函数做相反的一些清除工作。
函数init_mtd分析如下(在linux/drivers/mtd/mtd_core.c中): int __init init_mtd(void) {
if ((proc_mtd = create_proc_entry( “mtd”, 0, 0 ))) proc_mtd->read_proc = mtd_read_proc;
mtd_pm_dev = pm_register(PM_UNKNOWN_DEV, 0, mtd_pm_callback); return 0; }
static void __exit cleanup_mtd(void) {
if (mtd_pm_dev) {
pm_unregister(mtd_pm_dev); mtd_pm_dev = NULL; }
if (proc_mtd)
remove_proc_entry( “mtd”, 0); }
mtd_read_proc函数是proc系统调用到的最终读函数,它以字符形式读出结构struct mtd_info相关信息。
mtd_pm_callback函数通过各个设备的MTD设备结构mtd_info将电源管理请求传给具体的设备驱动程序。mtd_pm_callback函数列出如下:
static int mtd_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) {
int ret = 0, i;
if (down_trylock(&mtd_table_mutex)) return -EAGAIN;
if (rqst == PM_SUSPEND) {//电源挂起状态
for (i = 0; ret == 0 && i < MAX_MTD_DEVICES; i++) { if (mtd_table[i] && mtd_table[i]->suspend)
ret = mtd_table[i]->suspend(mtd_table[i]); }
} else i = MAX_MTD_DEVICES-1;
if (rqst == PM_RESUME || ret) {//电源恢复
for ( ; i >= 0; i--) {
if (mtd_table[i] && mtd_table[i]->resume) mtd_table[i]->resume(mtd_table[i]); } }
up(&mtd_table_mutex); return ret; }
MTD字符设备
当系统打开flash设备上的文件,它建立好了文件的操作函数集实例,当对文件操作时,就调用了这个文件操作函数集实例中的函数。当flash设备当作字符设备时,这些操作函数通过MTD设备的操作函数把数据直接读入/写出flash设备。 函数init_mtdchar注册了一个字符设备,列出如下(在drivers/mtd/mtdchar.c中):
static int __init init_mtdchar(void) {
if (register_chrdev(MTD_CHAR_MAJOR, “mtd”, &mtd_fops)) { printk(KERN_NOTICE “Can’t allocate major number %d for Memory Technology Devices.\\n”, MTD_CHAR_MAJOR); return -EAGAIN; }
mtdchar_devfs_init(); return 0; }
MTD字符设备的操作函数结构mtd_fops列出如下: static struct file_operations mtd_fops = {
.owner .llseek
= THIS_MODULE, = mtd_lseek,
};
.read .write .ioctl .open .release
= mtd_read, = mtd_write, = mtd_ioctl, = mtd_open, = mtd_close,
这里只分析了mtd_write函数,函数mtd_write完成此函数是对MTD字符设备的写操作。其中参数file是系统给MTD字符设备驱动程序用于传递参数的file结构,函数mtd_write通过file得到下层的MTD设备结构,参数buf是用户空间的指针,用于存放将要写入的数据,参数count是被写数据的长度,参数ppos是数据被写入MTD设备中的位置。当调用成功时返回返回实际读取数据的长度,若失败时返回错误码。 函数mtd_write分析如下:
static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count,loff_t *ppos) {
struct mtd_info *mtd = file->private_data; //得到MTD设备结构 char *kbuf; size_t retlen;
size_t total_retlen=0; int ret=0; int len;
DEBUG(MTD_DEBUG_LEVEL0,”MTD_write\\n”); if (*ppos == mtd->size) return -ENOSPC;
if (*ppos + count > mtd->size) count = mtd->size - *ppos;
if (!count) return 0; while (count) {