设备驱动学习之字符设备驱动内核代码分析(二)——字符设备结构体cdev
2013-05-14 22:28
381 查看
我们一般会将要实现的设备结构体定义如下:
struct my_cdev{
struct cdev dev;
...
};
struct cdev 就是内核提供的字符设备结构体,定义在linux/cdev.h 。个人认为我们实现的设备驱动结构体就是该结构体的子类。
下面是它的定义:
struct cdev {
struct kobject kobj;
struct module *owner;
const struct file_operations *ops;
struct list_head list;
dev_t dev;
unsigned int count;
};
其中对我们来说最重要的就是 const struct file_operations *ops,它指向了我们实现的文件操作函数。
结构体里还包含了 struct kobject kobj。说明struct cdev 是 struct kobject 的子类。 struct kobject 是内核里抽象的一个基础基类,不是太了解,以后专门研究一下再写篇笔记。
初始化struct cdev的接口是:
/**
* cdev_init() - initialize a cdev structure
* @cdev: the structure to initialize
* @fops: the file_operations for this device
*
* Initializes @cdev, remembering @fops, making it ready to add to the
* system with cdev_add().
*/
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{
memset(cdev, 0, sizeof *cdev);
INIT_LIST_HEAD(&cdev->list);
kobject_init(&cdev->kobj, &ktype_cdev_default);
cdev->ops = fops;
}
struct cdev 的初始化调用了kobject的初始化函数,位于lib/kobject.c ,如下:
/**
* kobject_init - initialize a kobject structure
* @kobj: pointer to the kobject to initialize
* @ktype: pointer to the ktype for this kobject.
*
* This function will properly initialize a kobject such that it can then
* be passed to the kobject_add() call.
*
* After this function is called, the kobject MUST be cleaned up by a call
* to kobject_put(), not by a call to kfree directly to ensure that all of
* the memory is cleaned up properly.
*/
void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
{
char *err_str;
if (!kobj) {
err_str = "invalid kobject pointer!";
goto error;
}
if (!ktype) {
err_str = "must have a ktype to be initialized properly!\n";
goto error;
}
if (kobj->state_initialized) {
/* do not error out as sometimes we can recover */
printk(KERN_ERR "kobject (%p): tried to init an initialized "
"object, something is seriously wrong.\n", kobj);
dump_stack();
}
kobject_init_internal(kobj); //前面都是防错编程,就这里是真正的初始化。
kobj->ktype = ktype;
return;
error:
printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
dump_stack();
}
static void kobject_init_internal(struct kobject *kobj)
{
if (!kobj)
return;
kref_init(&kobj->kref); //初始化引用计数为1,我猜的。。。
INIT_LIST_HEAD(&kobj->entry);
kobj->state_in_sysfs = 0;
kobj->state_add_uevent_sent = 0;
kobj->state_remove_uevent_sent = 0;
kobj->state_initialized = 1;
}
2013-6-4 增加:
其实实际的字符驱动程序这么简单,会利用linux设备模型的机制来编写驱动,将驱动描述和设备描述分离实现。具体参考linux platform。
struct my_cdev{
struct cdev dev;
...
};
struct cdev 就是内核提供的字符设备结构体,定义在linux/cdev.h 。个人认为我们实现的设备驱动结构体就是该结构体的子类。
下面是它的定义:
struct cdev {
struct kobject kobj;
struct module *owner;
const struct file_operations *ops;
struct list_head list;
dev_t dev;
unsigned int count;
};
其中对我们来说最重要的就是 const struct file_operations *ops,它指向了我们实现的文件操作函数。
结构体里还包含了 struct kobject kobj。说明struct cdev 是 struct kobject 的子类。 struct kobject 是内核里抽象的一个基础基类,不是太了解,以后专门研究一下再写篇笔记。
初始化struct cdev的接口是:
/**
* cdev_init() - initialize a cdev structure
* @cdev: the structure to initialize
* @fops: the file_operations for this device
*
* Initializes @cdev, remembering @fops, making it ready to add to the
* system with cdev_add().
*/
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{
memset(cdev, 0, sizeof *cdev);
INIT_LIST_HEAD(&cdev->list);
kobject_init(&cdev->kobj, &ktype_cdev_default);
cdev->ops = fops;
}
struct cdev 的初始化调用了kobject的初始化函数,位于lib/kobject.c ,如下:
/**
* kobject_init - initialize a kobject structure
* @kobj: pointer to the kobject to initialize
* @ktype: pointer to the ktype for this kobject.
*
* This function will properly initialize a kobject such that it can then
* be passed to the kobject_add() call.
*
* After this function is called, the kobject MUST be cleaned up by a call
* to kobject_put(), not by a call to kfree directly to ensure that all of
* the memory is cleaned up properly.
*/
void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
{
char *err_str;
if (!kobj) {
err_str = "invalid kobject pointer!";
goto error;
}
if (!ktype) {
err_str = "must have a ktype to be initialized properly!\n";
goto error;
}
if (kobj->state_initialized) {
/* do not error out as sometimes we can recover */
printk(KERN_ERR "kobject (%p): tried to init an initialized "
"object, something is seriously wrong.\n", kobj);
dump_stack();
}
kobject_init_internal(kobj); //前面都是防错编程,就这里是真正的初始化。
kobj->ktype = ktype;
return;
error:
printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
dump_stack();
}
static void kobject_init_internal(struct kobject *kobj)
{
if (!kobj)
return;
kref_init(&kobj->kref); //初始化引用计数为1,我猜的。。。
INIT_LIST_HEAD(&kobj->entry);
kobj->state_in_sysfs = 0;
kobj->state_add_uevent_sent = 0;
kobj->state_remove_uevent_sent = 0;
kobj->state_initialized = 1;
}
2013-6-4 增加:
其实实际的字符驱动程序这么简单,会利用linux设备模型的机制来编写驱动,将驱动描述和设备描述分离实现。具体参考linux platform。
相关文章推荐
- 设备驱动学习之字符设备驱动内核代码分析(一)——设备号申请接口
- 字符设备驱动浅析(内核代码分析)
- 字符设备驱动高级篇2——字符设备驱动注册代码分析
- __register_chrdev_region分析(简单字符设备驱动在内核的工作原理)
- 字符设备驱动代码完整分析
- Linux驱动学习5(详细分析字符设备驱动信号量实现互斥)
- 字符设备驱动在内核源码中的分析
- 基于mini6410的linux驱动学习总结(五 字符设备驱动程序实例分析(虚拟设备驱动))
- 使用内核定时器的second字符设备驱动及测试代码
- Linux内核部件分析<5> 设备驱动模型的基石kobject
- Linux设备驱动程序学习(基于2440的GPIO字符设备驱动)
- Hasen的linux设备驱动开发学习之旅--使用文件私有数据的字符设备驱动
- linux内核组件分析之--设备驱动模型之bus
- 基本字符设备的编写及代码分析
- 《LINUX设备驱动程序》学习之字符设备驱动实例
- 平台总线设备驱动模型——代码分析
- LDD3源码分析之字符设备驱动程序(加上测试代码)
- Linux设备驱动之mmap设备操作(memdev.c字符设备驱动分析)
- [Linux驱动]字符设备驱动学习笔记(二)———实例
- Linux 内核--总线设备驱动模型(字符/块/网络设备 && platform设备)