};
mtd_part结构是用于描述MTD原始设备分区的,结构mtd_part中的list成员链成一个链表mtd_partitons。每个mtd_part结构中的mtd_info结构用于描述本分区,被加入mtd_table数组中,其中mtd_info结构大部分成员由其主分区mtd_part->master决定,各种函数也指向主分区的相应函数。 结构mtd_part列出如下:
/* Our partition linked list */ static LIST_HEAD(mtd_partitions); 的链表
struct mtd_part { struct mtd_info mtd; 决定) struct mtd_info *master; u_int32_t offset; int index; struct list_head list; };
结构mtd_partition描述mtd设备分区的结构,在MTD原始设备层调用函数add_mtd_partions时传递分区信息使用。结构列出如下(在include/linux/mtd/partition.h中):
struct mtd_partition { char *name; //分区名 u_int32_t size; //分区大小 u_int32_t offset; //在主MTD空间的偏移 u_int32_t mask_flags; };
MTD原始设备分区
//分区的信息(大部分由其master//该分区的主分区 //该分区的偏移地址 //分区号
MTD块设备初始化
图 函数init_mtdblock调用层次图
在具体的设备驱动程序初始化时,它会添加一个MTD设备结构到mtd_table数组中。MTD翻译层通过查找这个数组,可访问到各个具体设备驱动程序。 函数init_mtdblock注册一个MTD翻译层设备,初始化处理请求的线程,赋上MTD翻译层设备操作函数集实例,注册这个设备的通用硬盘结构。函数init_mtdblock调用层次图如上图。
mtd块设备驱动程序利用一个线程,当有读写请求时,从缓冲区将数据写入块设备或从块设备读入到缓冲区中。
函数init_mtdblock分析如下(在drivers/mtd/mtdblock.c中): static int __init init_mtdblock(void) {
return register_mtd_blktrans(&mtdblock_tr); }
MTD翻译层设备操作函数集实例列出如下: static struct mtd_blktrans_ops mtdblock_tr = {
};
.name .major .part_bits .open .flush .release .readsect .writesect .add_mtd .remove_dev .owner
= “mtdblock”, = 31, = 0,
= mtdblock_open, = mtdblock_flush, = mtdblock_release, = mtdblock_readsect, = mtdblock_writesect, = mtdblock_add_mtd, = mtdblock_remove_dev, = THIS_MODULE,
static LIST_HEAD(blktrans_majors);
int register_mtd_blktrans(struct mtd_blktrans_ops *tr) {
int ret, i;
//如果第一个设备类型被注册了,注册notifier来阻止
/* Register the notifier if/when the first device type is registered, to prevent the link/init ordering from fucking us over. */
if (!blktrans_notifier.list.next)//如果不存在
//注册MTD翻译层块设备,创建通用硬盘结构并注册 register_mtd_user(&blktrans_notifier);
tr->blkcore_priv = kmalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL);
if (!tr->blkcore_priv) return -ENOMEM;
memset(tr->blkcore_priv, 0, sizeof(*tr->blkcore_priv)); down(&mtd_table_mutex);
//创建blk_major_name结构初始化后加到&major_names[]数组中 ret = register_blkdev(tr->major, tr->name);
?
spin_lock_init(&tr->blkcore_priv->queue_lock); init_completion(&tr->blkcore_priv->thread_dead); init_waitqueue_head(&tr->blkcore_priv->thread_wq);
//创建请求队列并初始化,赋上块设备特定的请求处理函数mtd_blktrans_request
tr->blkcore_priv->rq = blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue_lock);
?
tr->blkcore_priv->rq->queuedata = tr;//赋上MTD翻译层块设备操作函数集
//创建线程mtd_blktrans_thread
ret = kernel_thread(mtd_blktrans_thread, tr, CLONE_KERNEL);
?
//在devfs文件系统中创建设备的目录名 devfs_mk_dir(tr->name);
INIT_LIST_HEAD(&tr->devs);//初始化设备的链表 list_add(&tr->list, &blktrans_majors); for (i=0; i if (mtd_table[i] && mtd_table[i]->type != MTD_ABSENT) //创建MTD翻译层设备结构并初始化,然后到MTD设备链表中 tr->add_mtd(tr, mtd_table[i]); } up(&mtd_table_mutex); return 0; } 函数mtd_blktrans_request是MTD设备的请求处理函数,当请求队列中的请求需要设备处理时调用这个函数。在MTD设备中,函数mtd_blktrans_request唤醒了MTD块设备的线程来进行处理。函数列出如下(在drivers/mtd/mtd_blkdevs.c中): static void mtd_blktrans_request(struct request_queue *rq) { struct mtd_blktrans_ops *tr = rq->queuedata; wake_up(&tr->blkcore_priv->thread_wq); } 线程函数mtd_blktrans_thread处理块设备的读写请求,函数mtd_blktrans_thread列出如下: static int mtd_blktrans_thread(void *arg) { struct mtd_blktrans_ops *tr = arg; struct request_queue *rq = tr->blkcore_priv->rq; /* we might get involved when memory gets low, so use PF_MEMALLOC */ current->flags |= PF_MEMALLOC | PF_NOFREEZE; //变成以init为父进程的后台进程