设备驱动学习之字符设备驱动内核代码分析(二)——字符设备结构体cdev

来源:互联网 发布:谷歌关键词优化 编辑:程序博客网 时间:2024/04/30 12:40

我们一般会将要实现的设备结构体定义如下:

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。