Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3167870
  • 博文数量: 685
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 5303
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-19 14:17
个人简介

文章分类

全部博文(685)

文章存档

2015年(116)

2014年(569)

分类: 嵌入式

2014-10-27 12:45:09

原文地址:http://blog.csdn.net/wang_zheng_kai/article/details/19038471

三、MTD创建设备节点

MTD子系统下如何创建设备节点?

第一步:MTD设备层。(MTD子系统)

  register_chrdev注册字符型mtd设备,并添加该设备到内核,主设备号为90。但是此时还未在/dev下形成mtd设备节点。

第二步:MTD原始设备层。(MTD子系统)

  class_register注册一个mtd类mtd_class,后面再注册mtd设备时会用到该class。

第三步:驱动层。(调用接口完成)

  在添加MTD设备同时,在原始设备层注册的那个class接口上创建了设备节点。/dev/mtdXXX出现

内核和驱动中代码执行的流程:

  1)mtdchar.c:

       init_mtdchar ---> __register_chrdev();---> cdev_add

  2)mtdcore.c:

       init_mtd --->class_register(&mtd_class);//创建mtd类

 3)jz4780_nand.c:

      device_create(); ---> add_mtd_partitions---> add_mtd_device

             ---> device_create();

其程序代码分析如下图所示:


  1. 关于设备节点的创建  
  2. 一》MTD设备层  
  3. static int __init init_mtdchar(void)  
  4. {  
  5.         int ret;  
  6.         ret = __register_chrdev(MTD_CHAR_MAJOR, 01 << MINORBITS,  
  7.                             "mtd", &mtd_fops);  
  8. //申请设备号并注册  
  9.         if (ret < 0) {  
  10.                 pr_notice("Can't allocate major number %d for "  
  11.                                 "Memory Technology Devices.\n", MTD_CHAR_MAJOR);  
  12.                 return ret;  
  13.         }  
  14.   
  15.         ret = register_filesystem(&mtd_inodefs_type);  
  16.         //注册mtd_inodefs_type文件系统  
  17.         if (ret) {  
  18.                 pr_notice("Can't register mtd_inodefs filesystem: %d\n", ret);  
  19.                 goto err_unregister_chdev;  
  20.         }  
  21.         return ret;  
  22.   
  23. err_unregister_chdev:  
  24.         __unregister_chrdev(MTD_CHAR_MAJOR, 01 << MINORBITS, "mtd");  
  25.         //释放设备号  
  26.         return ret;  
  27. }  
  28.   
  29.   
  30. int __register_chrdev(unsigned int major, unsigned int baseminor,  
  31.                       unsigned int count, const charchar *name,  
  32.                       const struct file_operations *fops)  
  33. {  
  34.         struct char_device_struct *cd;  
  35.         struct cdev *cdev;  
  36.         int err = -ENOMEM;  
  37.         cd = __register_chrdev_region(major, baseminor, count, name);  
  38.   
  39.         if (IS_ERR(cd))  
  40.                 return PTR_ERR(cd);  
  41.         cdev = cdev_alloc();  
  42.         if (!cdev)  
  43.                 goto out2;  
  44.         cdev->owner = fops->owner;  
  45.   
  46.         cdev->ops = fops;  
  47.         kobject_set_name(&cdev->kobj, "%s", name);  
  48.         err = cdev_add(cdev, MKDEV(cd->major, baseminor), count);  
  49.   
  50.         if (err)  
  51.                 goto out;  
  52.         cd->cdev = cdev;  
  53.         return major ? 0 : cd->major;  
  54. out:  
  55.         kobject_put(&cdev->kobj);  
  56. out2:  
  57.         kfree(__unregister_chrdev_region(cd->major, baseminor, count));  
  58.         return err;  
  59. }  
  60.   
  61. 流程:  
  62.   init_mtdchar ------>__register_chrdev(MTD_CHAR_MAJOR, 01 << MINORBITS,"mtd", &mtd_fops);------>cdev_add   
  63.   
  64. 分析:这是创建设备节点的第一步:MTD设备层。  
  65. register_chrdev注册字符型mtd设备,并添加该设备到内核,主设备号为90。但是要注意的是此时还未在/dev下形成mtd设备节点。  
  66.   
  67. 二》MTD原始设备层  
  68.   
  69. static int __init init_mtd(void)  
  70. {  
  71.         int ret;  
  72.   
  73.         ret = class_register(&mtd_class);//创建mtd类  
  74.   
  75.         if (ret)  
  76.                 goto err_reg;  
  77.         ret = mtd_bdi_init(&mtd_bdi_unmappable, "mtd-unmap");//支持无映射设备  
  78.         if (ret)  
  79.                 goto err_bdi1;  
  80.         ret = mtd_bdi_init(&mtd_bdi_ro_mappable, "mtd-romap");//支持R/O映射设备  
  81.         if (ret)  
  82.                 goto err_bdi2;  
  83.         ret = mtd_bdi_init(&mtd_bdi_rw_mappable, "mtd-rwmap");//支持可写可映射设备  
  84.         if (ret)  
  85.                 goto err_bdi3;  
  86. #ifdef CONFIG_PROC_FS  
  87.         proc_mtd = proc_create("mtd"0NULL, &mtd_proc_ops);//创建proc文件体系接口"/proc/mtd"  
  88. #endif /* CONFIG_PROC_FS */  
  89.         return 0;  
  90. err_bdi3:  
  91.         bdi_destroy(&mtd_bdi_ro_mappable);  
  92. err_bdi2:  
  93.         bdi_destroy(&mtd_bdi_unmappable);  
  94. err_bdi1:  
  95.         class_unregister(&mtd_class);  
  96. err_reg:  
  97.         pr_err("Error registering mtd class or bdi: %d\n", ret);  
  98.         return ret;  
  99. }  
  100.   
  101.   
  102. 流程:  
  103.  init_mtd -> ret = class_register(&mtd_class);  
  104. 分析:这是创建设备节点的第二步:MTD原始设备层。(MTD子系统)  
  105.  class_register注册一个mtd类mtd_class,后面再注册mtd设备时会用到该class。  
  106.   
  107.   
  108.   
  109. 三》驱动层  
  110.   
  111. static int jz4780_nand_probe(struct platform_device *pdev)  
  112. {  
  113.   /* 
  114.          * MTD register 
  115.          */  
  116.         ret = mtd_device_parse_register(mtd, NULLNULL,  
  117.                         pdata->part_table, pdata->num_part);  
  118.         if (ret) {  
  119.                 dev_err(&pdev->dev, "Failed to add MTD device\n");  
  120.                 goto err_unreloc_hot;  
  121.         }  
  122. }  
  123. int mtd_device_parse_register(struct mtd_info *mtd, const charchar **types,  
  124.                               struct mtd_part_parser_data *parser_data,  
  125.                               const struct mtd_partition *parts,  
  126.                               int nr_parts)  
  127. {  
  128.         int err;  
  129.         struct mtd_partition *real_parts;  
  130.   
  131.         err = parse_mtd_partitions(mtd, types, &real_parts, parser_data);  
  132.   
  133.         if (err <= 0 && nr_parts && parts) {  
  134.                 real_parts = kmemdup(parts, sizeof(*parts) * nr_parts,  
  135.                                      GFP_KERNEL);  
  136.                 if (!real_parts)  
  137.                         err = -ENOMEM;  
  138.                 else   
  139.                         err = nr_parts;  
  140.         }  
  141.   
  142.         if (err > 0) {  
  143.                 err = add_mtd_partitions(mtd, real_parts, err);  
  144.                 kfree(real_parts);  
  145.         } else if (err == 0) {  
  146.                 err = add_mtd_device(mtd);  
  147.                 if (err == 1)  
  148.                         err = -ENODEV;  
  149.         }                   
  150.         return err;  
  151. }         
  152.   
  153. EXPORT_SYMBOL_GPL(mtd_device_parse_register);  
  154.   
  155. int add_mtd_device(struct mtd_info *mtd)  
  156. {  
  157.         struct mtd_notifier *not;  
  158.         int i, error;  
  159.         //设置mtd_info结构体信息  
  160.         if (!mtd->backing_dev_info) {  
  161.                 switch (mtd->type) {  
  162.                 case MTD_RAM:  
  163.                         mtd->backing_dev_info = &mtd_bdi_rw_mappable;  
  164.                         break;  
  165.                 case MTD_ROM:  
  166.                         mtd->backing_dev_info = &mtd_bdi_ro_mappable;  
  167.                         break;  
  168.                 default:  
  169.                         mtd->backing_dev_info = &mtd_bdi_unmappable;  
  170.                         break;  
  171.                 }  
  172.         }  
  173.   
  174.         BUG_ON(mtd->writesize == 0);//mtd写操作单位不能为0  
  175.         mutex_lock(&mtd_table_mutex);//初始化mtd_table_mutex,上锁  
  176.   
  177.         do {  
  178.                 if (!idr_pre_get(&mtd_idr, GFP_KERNEL))//为mtd_idr分配内存  
  179.                         goto fail_locked;  
  180.                 error = idr_get_new(&mtd_idr, mtd, &i);//将mtd_idr和id关联起来  
  181.         } while (error == -EAGAIN);//判断是否上锁,否则会报错  
  182.   
  183.         if (error)  
  184.                 goto fail_locked;  
  185.   
  186.         mtd->index = i;//索引值设为当前数组项的下标  
  187.         mtd->usecount = 0;//引用计数设为零  
  188.  /* default value if not set by driver *///没有被设置的话将会被设置成默认值  
  189.         if (mtd->bitflip_threshold == 0)  
  190.                 mtd->bitflip_threshold = mtd->ecc_strength;  
  191.         if (is_power_of_2(mtd->erasesize))//最小的擦出块大小  
  192.                 mtd->erasesize_shift = ffs(mtd->erasesize) - 1;  
  193.         else  
  194.                 mtd->erasesize_shift = 0;  
  195.         if (is_power_of_2(mtd->writesize))//编程块大小  
  196.                 mtd->writesize_shift = ffs(mtd->writesize) - 1;  
  197.         else  
  198.                 mtd->writesize_shift = 0;  
  199.         mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1;  
  200.         mtd->writesize_mask = (1 << mtd->writesize_shift) - 1;  
  201.         /* Some chips always power up locked. Unlock them now */  
  202.         if ((mtd->flags & MTD_WRITEABLE) && (mtd->flags & MTD_POWERUP_LOCK)) {  
  203.                 error = mtd_unlock(mtd, 0, mtd->size);  
  204.                 if (error && error != -EOPNOTSUPP)  
  205.                         printk(KERN_WARNING  
  206.                                "%s: unlock failed, writes may not work\n",  
  207.                                mtd->name);  
  208.         }  
  209.         /* Caller should have set dev.parent to match the 
  210.          * physical device. 
  211.          */  
  212.         mtd->dev.type = &mtd_devtype;  
  213.         mtd->dev.class = &mtd_class;  
  214.         mtd->dev.devt = MTD_DEVT(i);  
  215.         dev_set_name(&mtd->dev, "mtd%d", i);//设置mtd设备名  
  216.         dev_set_drvdata(&mtd->dev, mtd);//设置mtd设备信息mtd_info  
  217.         if (device_register(&mtd->dev) != 0)//注册设备  
  218.                 goto fail_added;  
  219.         if (MTD_DEVT(i))//创建设备  
  220.                 device_create(&mtd_class, mtd->dev.parent,  
  221.                               MTD_DEVT(i) + 1,  
  222.                               NULL"mtd%dro", i);  
  223.         pr_debug("mtd: Giving out device %d to %s\n", i, mtd->name);  
  224.   /* No need to get a refcount on the module containing 
  225.            the notifier, since we hold the mtd_table_mutex */  
  226.         //遍历list链表将每一个mtd_notifier执行add()函数,对新加入的mtd设备操作,通知所有的MTD user新的MTD设备的到来  
  227.         list_for_each_entry(not, &mtd_notifiers, list)  
  228.                 not->add(mtd);  
  229.   
  230.         mutex_unlock(&mtd_table_mutex);//解锁信号量  
  231.         /* We _know_ we aren't being removed, because 
  232.            our caller is still holding us here. So none 
  233.            of this try_ nonsense, and no bitching about it 
  234.            either. :) */  
  235.         __module_get(THIS_MODULE);  
  236.         return 0;  
  237.   
  238. fail_added:  
  239.         idr_remove(&mtd_idr, i);  
  240. fail_locked:  
  241.         mutex_unlock(&mtd_table_mutex);  
  242.         return 1;  
  243. }  
  244. 流程:  
  245.   device_create(&mtd_class, mtd->dev.parent,MTD_DEVT(i) + 1,NULL"mtd%dro", i);->add_mtd_partitions->add_mtd_device-> device_create(&mtd_class, mtd->dev.parent,MTD_DEVT(i) + 1,NULL"mtd%dro", i);  
  246.   
  247. 分析:这是创建设备节点的第三步:驱动层.  
  248. 在添加MTD设备同时,在原始设备层注册的那个class接口上创建了设备节点。/dev/mtdXXX出现  


阅读(1282) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~