NAND FLASH学习笔记之MTD下nand flash驱动(三)
三、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(); 其程序代码分析如下图所示:
关于设备节点的创建 一》MTD设备层 static int __init init_mtdchar(void) { int ret; ret = __register_chrdev(MTD_CHAR_MAJOR,1 << MINORBITS,"mtd",&mtd_fops); //申请设备号并注册 if (ret < 0) { pr_notice("Can't allocate major number %d for " "Memory Technology Devices.n",MTD_CHAR_MAJOR); return ret; } ret = register_filesystem(&mtd_inodefs_type); //注册mtd_inodefs_type文件系统 if (ret) { pr_notice("Can't register mtd_inodefs filesystem: %dn",ret); goto err_unregister_chdev; } return ret; err_unregister_chdev: __unregister_chrdev(MTD_CHAR_MAJOR,"mtd"); //释放设备号 return ret; } int __register_chrdev(unsigned int major,unsigned int baseminor,unsigned int count,const char *name,const struct file_operations *fops) { struct char_device_struct *cd; struct cdev *cdev; int err = -ENOMEM; cd = __register_chrdev_region(major,baseminor,count,name); if (IS_ERR(cd)) return PTR_ERR(cd); cdev = cdev_alloc(); if (!cdev) goto out2; cdev->owner = fops->owner; cdev->ops = fops; kobject_set_name(&cdev->kobj,"%s",name); err = cdev_add(cdev,MKDEV(cd->major,baseminor),count); if (err) goto out; cd->cdev = cdev; return major ? 0 : cd->major; out: kobject_put(&cdev->kobj); out2: kfree(__unregister_chrdev_region(cd->major,count)); return err; } 流程: init_mtdchar ------>__register_chrdev(MTD_CHAR_MAJOR,&mtd_fops);------>cdev_add 分析:这是创建设备节点的第一步:MTD设备层。 register_chrdev注册字符型mtd设备,并添加该设备到内核,主设备号为90。但是要注意的是此时还未在/dev下形成mtd设备节点。 二》MTD原始设备层 static int __init init_mtd(void) { int ret; ret = class_register(&mtd_class);//创建mtd类 if (ret) goto err_reg; ret = mtd_bdi_init(&mtd_bdi_unmappable,"mtd-unmap");//支持无映射设备 if (ret) goto err_bdi1; ret = mtd_bdi_init(&mtd_bdi_ro_mappable,"mtd-romap");//支持R/O映射设备 if (ret) goto err_bdi2; ret = mtd_bdi_init(&mtd_bdi_rw_mappable,"mtd-rwmap");//支持可写可映射设备 if (ret) goto err_bdi3; #ifdef CONFIG_PROC_FS proc_mtd = proc_create("mtd",NULL,&mtd_proc_ops);//创建proc文件体系接口"/proc/mtd" #endif /* CONFIG_PROC_FS */ return 0; err_bdi3: bdi_destroy(&mtd_bdi_ro_mappable); err_bdi2: bdi_destroy(&mtd_bdi_unmappable); err_bdi1: class_unregister(&mtd_class); err_reg: pr_err("Error registering mtd class or bdi: %dn",ret); return ret; } 流程: init_mtd -> ret = class_register(&mtd_class); 分析:这是创建设备节点的第二步:MTD原始设备层。(MTD子系统) class_register注册一个mtd类mtd_class,后面再注册mtd设备时会用到该class。 三》驱动层 static int jz4780_nand_probe(struct platform_device *pdev) { /* * MTD register */ ret = mtd_device_parse_register(mtd,pdata->part_table,pdata->num_part); if (ret) { dev_err(&pdev->dev,"Failed to add MTD devicen"); goto err_unreloc_hot; } } int mtd_device_parse_register(struct mtd_info *mtd,const char **types,struct mtd_part_parser_data *parser_data,const struct mtd_partition *parts,int nr_parts) { int err; struct mtd_partition *real_parts; err = parse_mtd_partitions(mtd,types,&real_parts,parser_data); if (err <= 0 && nr_parts && parts) { real_parts = kmemdup(parts,sizeof(*parts) * nr_parts,GFP_KERNEL); if (!real_parts) err = -ENOMEM; else err = nr_parts; } if (err > 0) { err = add_mtd_partitions(mtd,real_parts,err); kfree(real_parts); } else if (err == 0) { err = add_mtd_device(mtd); if (err == 1) err = -ENODEV; } return err; } EXPORT_SYMBOL_GPL(mtd_device_parse_register); int add_mtd_device(struct mtd_info *mtd) { struct mtd_notifier *not; int i,error; //设置mtd_info结构体信息 if (!mtd->backing_dev_info) { switch (mtd->type) { case MTD_RAM: mtd->backing_dev_info = &mtd_bdi_rw_mappable; break; case MTD_ROM: mtd->backing_dev_info = &mtd_bdi_ro_mappable; break; default: mtd->backing_dev_info = &mtd_bdi_unmappable; break; } } BUG_ON(mtd->writesize == 0);//mtd写操作单位不能为0 mutex_lock(&mtd_table_mutex);//初始化mtd_table_mutex,上锁 do { if (!idr_pre_get(&mtd_idr,GFP_KERNEL))//为mtd_idr分配内存 goto fail_locked; error = idr_get_new(&mtd_idr,mtd,&i);//将mtd_idr和id关联起来 } while (error == -EAGAIN);//判断是否上锁,否则会报错 if (error) goto fail_locked; mtd->index = i;//索引值设为当前数组项的下标 mtd->usecount = 0;//引用计数设为零 /* default value if not set by driver *///没有被设置的话将会被设置成默认值 if (mtd->bitflip_threshold == 0) mtd->bitflip_threshold = mtd->ecc_strength; if (is_power_of_2(mtd->erasesize))//最小的擦出块大小 mtd->erasesize_shift = ffs(mtd->erasesize) - 1; else mtd->erasesize_shift = 0; if (is_power_of_2(mtd->writesize))//编程块大小 mtd->writesize_shift = ffs(mtd->writesize) - 1; else mtd->writesize_shift = 0; mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1; mtd->writesize_mask = (1 << mtd->writesize_shift) - 1; /* Some chips always power up locked. Unlock them now */ if ((mtd->flags & MTD_WRITEABLE) && (mtd->flags & MTD_POWERUP_LOCK)) { error = mtd_unlock(mtd,mtd->size); if (error && error != -EOPNOTSUPP) printk(KERN_WARNING "%s: unlock failed,writes may not workn",mtd->name); } /* Caller should have set dev.parent to match the * physical device. */ mtd->dev.type = &mtd_devtype; mtd->dev.class = &mtd_class; mtd->dev.devt = MTD_DEVT(i); dev_set_name(&mtd->dev,"mtd%d",i);//设置mtd设备名 dev_set_drvdata(&mtd->dev,mtd);//设置mtd设备信息mtd_info if (device_register(&mtd->dev) != 0)//注册设备 goto fail_added; if (MTD_DEVT(i))//创建设备 device_create(&mtd_class,mtd->dev.parent,MTD_DEVT(i) + 1,"mtd%dro",i); pr_debug("mtd: Giving out device %d to %sn",i,mtd->name); /* No need to get a refcount on the module containing the notifier,since we hold the mtd_table_mutex */ //遍历list链表将每一个mtd_notifier执行add()函数,对新加入的mtd设备操作,通知所有的MTD user新的MTD设备的到来 list_for_each_entry(not,&mtd_notifiers,list) not->add(mtd); mutex_unlock(&mtd_table_mutex);//解锁信号量 /* We _know_ we aren't being removed,because our caller is still holding us here. So none of this try_ nonsense,and no bitching about it either. :) */ __module_get(THIS_MODULE); return 0; fail_added: idr_remove(&mtd_idr,i); fail_locked: mutex_unlock(&mtd_table_mutex); return 1; } 流程: device_create(&mtd_class,i);->add_mtd_partitions->add_mtd_device-> device_create(&mtd_class,i); 分析:这是创建设备节点的第三步:驱动层. 在添加MTD设备同时,在原始设备层注册的那个class接口上创建了设备节点。/dev/mtdXXX出现 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |