加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

NAND FLASH学习笔记之MTD下nand flash驱动(三)

发布时间:2020-12-15 17:44:08 所属栏目:百科 来源:网络整理
导读:三、MTD创建设备节点 MTD子系统下如何创建设备节点? 第一步:MTD设备层。(MTD子系统) ??register_chrdev注册字符型mtd设备,并添加该设备到内核,主设备号为90。但是此时还未在/dev下形成mtd设备节点。 第二步:MTD原始设备层。(MTD子系统) ??class_reg

三、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出现

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读