mtd学习报告002

初始化

   这里我们先说一下几个重要的全局变量:

  

   /drivers/mtd/mtdcore.c

   struct mtd_info *mtd_table[MAX_MTD_DEVICES];

   该数组中保存了所有的MTD原始设备,

 

   以学习报告001的编译配置为前提,该部分的初始化主要包括mtd部分的和nand部分的。我们要分析的就是前面提到的几个重要文件。至于如何看各个文件是否有初始化的接口,就按模块编写的方式查看有无module_init(init_func)的定义了。

  

/driver/mtd/mtdcore.c:

module_init(init_mtd);   

module_exit(cleanup_mtd);

 

   很明显init_mtd就是会在系统启动时被调用来初始化的函数。我们看这个函数:

 

/driver/mtd/mtdcore.c:

static int __init init_mtd(void)

{

#ifdef CONFIG_PROC_FS

       if ((proc_mtd = create_proc_entry( "mtd", 0, NULL )))

              proc_mtd->read_proc = mtd_read_proc;

#endif

 

#ifdef CONFIG_PM

       mtd_pm_dev = pm_register(PM_UNKNOWN_DEV, 0, mtd_pm_callback);

#endif

       return 0;

}

    该函数首先在proc文件系统下创建一个保存所有mtd设备信息的目录, 接着注册一个read函数用来读取这个目录下的内容, 最后注册了一个电源管理方面的函数,因为跟分析MTD本身关系不是很到,我们略过。

mtdcore.c里主要export了很多函数, add_mtd_device(), del_mtd_device(), 我们会看到别的部分是如何使用这些export的函数.

   接着看mtdpart.c,里面并没有初始化函数,也仅仅是export出来了很多的函数接口, 该文件主要提供了

操作分区方面的API。我们在调用这些函数的时候再来分析他们.

 

在看mtdchar.c:

 

/driver/mtd/mtdchar.c:

module_init(init_mtdchar);

module_exit(cleanup_mtdchar);

 

初始化函数为: init_mtdchar

 

/driver/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_CHAR_MAJOR的字符设备文件对应的文件操作集为mtd_fops。字符设备文件将在系统检测到flash设备时创建。

 

    /driver/mtd/mtdchar.c:

    static struct file_operations mtd_fops = {

       .owner           = THIS_MODULE,

       .llseek            = mtd_lseek,

       .read              = mtd_read,

       .write             = mtd_write,

       .ioctl              = mtd_ioctl,

       .open             = mtd_open,

       .release   = mtd_close,

};

由此可以知道当用户在用户层通过系统调用read函数时将会传递到这里注册的mtd_read函数。

 

接着调用mtdchar_devfs_init()来在devfs下创建mtdchar

 

/driver/mtd/mtdchar.c:

static inline void mtdchar_devfs_init(void)

{

       devfs_mk_dir("mtd");    /*创建一个mtd的目录*/

       register_mtd_user(&notifier);   /*注册一个notify机器*/

}

   接着看一下register_mtd_user()函数:

 

/driver/mtd/mtdchar.c:

void register_mtd_user (struct mtd_notifier *new)

{

       int i;

 

       down(&mtd_table_mutex);

 

       list_add(&new->list, &mtd_notifiers);  /*添加到mtd_notifiers列表中去*/

 

      __module_get(THIS_MODULE);

      

    /*对于每个已存在的mtd设备调用notifyadd函数*/

       for (i=0; i< MAX_MTD_DEVICES; i++)

              if (mtd_table[i])

                     new->add(mtd_table[i]);

 

       up(&mtd_table_mutex);

}

/driver/mtd/mtdchar.c:

static struct mtd_notifier notifier = {

       .add = mtd_notify_add,

       .remove  = mtd_notify_remove,

};

随后我们会看到每当有新的mtd设备要注册时都会调用这些notifieradd函数, 以通知这些notifier有新的mtd设备注册了, 然后我们的notifier就可以为这个mtd做相应的初始化工作了.

 

OK, 我们重点看下mtd block部分,因为我们以s3c2410flash为例, 一般nand flash都是block设备.

 

Drivers/mtd/mtdblock.c:

module_init(init_mtdblock);

/*初始化函数*/

static int __init init_mtdblock(void)

{

   return register_mtd_blktrans(&mtdblock_tr);

}

该函数注册了一套操作函数集,  以后我们会看到是如何使用的,  mtdblock_tr的定义如下

static struct mtd_blktrans_ops mtdblock_tr = {

   .name            = "mtdblock",

   .major            = 31,

   .part_bits = 0,

   .open             = mtdblock_open,

   .flush             = mtdblock_flush,

   .release   = mtdblock_release,

   .readsect = mtdblock_readsect,

   .writesect       = mtdblock_writesect,

   .add_mtd = mtdblock_add_mtd,

   .remove_dev  = mtdblock_remove_dev,

   .owner           = THIS_MODULE,

};

 

Drivers/mtd/mtd_blkdevs.c:

int register_mtd_blktrans(struct mtd_blktrans_ops *tr)

{

   int ret, i;

 

   /* 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)

          register_mtd_user(&blktrans_notifier);    /*注册一个notifyer, char的一样,以后会用到*/

 

/*定义一个私有对象,用以保存信息*/

   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);

 

   ret = register_blkdev(tr->major, tr->name);    /*注册一个block设备, 具体可参考block驱动的编写*/

   if (ret) {

          printk(KERN_WARNING "Unable to register %s block device on major %d: %d/n",

                 tr->name, tr->major, ret);

          kfree(tr->blkcore_priv);

          up(&mtd_table_mutex);

          return ret;

   }

  /*做初始化工作, 这些都是block驱动必须的东西*/

   spin_lock_init(&tr->blkcore_priv->queue_lock);

   init_completion(&tr->blkcore_priv->thread_dead);

   init_waitqueue_head(&tr->blkcore_priv->thread_wq);

 

   tr->blkcore_priv->rq = blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue_lock);

   if (!tr->blkcore_priv->rq) {

          unregister_blkdev(tr->major, tr->name);

          kfree(tr->blkcore_priv);

          up(&mtd_table_mutex);

          return -ENOMEM;

   }

 

   tr->blkcore_priv->rq->queuedata = tr;

 

  /*创建一个线程, 用来处理用户层对block设备的各种请求*/

   ret = kernel_thread(mtd_blktrans_thread, tr, CLONE_KERNEL);

   if (ret < 0) {

          blk_cleanup_queue(tr->blkcore_priv->rq);

          unregister_blkdev(tr->major, tr->name);

          kfree(tr->blkcore_priv);

          up(&mtd_table_mutex);

          return ret;

   }

 

   devfs_mk_dir(tr->name);

 

   INIT_LIST_HEAD(&tr->devs);

   list_add(&tr->list, &blktrans_majors);

 

  /*如果已有mtd设备存在, 则调用notifieradd回调函数*/

   for (i=0; i<MAX_MTD_DEVICES; i++) {

          if (mtd_table[i] && mtd_table[i]->type != MTD_ABSENT)

                 tr->add_mtd(tr, mtd_table[i]);

   }

 

   up(&mtd_table_mutex);

 

   return 0;

}

 

blktrans_notifier

static struct mtd_notifier blktrans_notifier = {

   .add = blktrans_notify_add,   /*当有新设备添加的时候调用这个函数*/

   .remove = blktrans_notify_remove,  /*当有设备移除的时候调用这个函数*/

};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值