原文地址:
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();
其程序代码分析如下图所示:
-
关于设备节点的创建
-
一》MTD设备层
-
static int __init init_mtdchar(void)
-
{
-
int ret;
-
ret = __register_chrdev(MTD_CHAR_MAJOR, 0, 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: %d\n", ret);
-
goto err_unregister_chdev;
-
}
-
return ret;
-
-
err_unregister_chdev:
-
__unregister_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, "mtd");
-
//释放设备号
-
return ret;
-
}
-
-
-
int __register_chrdev(unsigned int major, unsigned int baseminor,
-
unsigned int count, const charchar *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, baseminor, count));
-
return err;
-
}
-
-
流程:
-
init_mtdchar ------>__register_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS,"mtd", &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", 0, 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: %d\n", 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, NULL, NULL,
-
pdata->part_table, pdata->num_part);
-
if (ret) {
-
dev_err(&pdev->dev, "Failed to add MTD device\n");
-
goto err_unreloc_hot;
-
}
-
}
-
int mtd_device_parse_register(struct mtd_info *mtd, const charchar **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, 0, mtd->size);
-
if (error && error != -EOPNOTSUPP)
-
printk(KERN_WARNING
-
"%s: unlock failed, writes may not work\n",
-
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,
-
NULL, "mtd%dro", i);
-
pr_debug("mtd: Giving out device %d to %s\n", 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, 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);
-
-
分析:这是创建设备节点的第三步:驱动层.
-
在添加MTD设备同时,在原始设备层注册的那个class接口上创建了设备节点。/dev/mtdXXX出现
阅读(1282) | 评论(0) | 转发(0) |