cdev_init的分析
在内核的角度来看,一个cdev结构体就是一个字符设备。
struct cdev {
struct kobject kobj; // 内嵌的内核对象.
struct module *owner; //该字符设备所在的内核模块的对象指针.
const struct file_operations *ops; //该结构描述了字符设备所能实现的方法,即file_operations.
struct list_head list; //用来将已经向内核注册的所有字符设备形成链表.
dev_t dev; //字符设备的设备号,由主设备号和次设备号构成.
unsigned int count; //隶属于同一主设备号的次设备号的个数.
} __randomize_layout;
cdev_init()函数源码
/**
* cdev_init() - 初始化一个cdev结构体
* @cdev: 将要被初始化的结构体指针
* @fops: 该设备对应的文件操作函数
*/
void cdev_init(struct cdev *cdev, struct file_operations *fops)
{
memset(cdev, 0, sizeof *cdev); //首先将cdev对应的空间进行清零操作
INIT_LIST_HEAD(&cdev->list); // 初始化list变量为双向环形链表的头结点
cdev->kobj.ktype = &ktype_cdev_default;
kobject_init(&cdev->kobj);
cdev->ops = fops;
}
// 初始化list域的next指针和prev指针指向自己。
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
struct kref {
atomic_t refcount;
};
// 内核对象
struct kobject {
/**
* 指向容器名称。
*/
char * k_name;
/**
* 如果容器名称不超过20个字符,就存在这里。
*/
char name[KOBJ_NAME_LEN];
/**
* 容器的引用计数。
*/
struct kref kref;
/**
* 用于将kobject插入某个链表。
*/
struct list_head entry;
/**
* 指向父kobject
*/
struct kobject * parent;
/**
* 指向包含的kset,kset是同类型的kobject结构的一个集合体。
*/
struct kset * kset;
/**
* 指向kobject的类型描述符。
*/
struct kobj_type * ktype;
/**
* 指向与kobject对应的sysfs文件的dentry数据结构。
*/
struct dentry * dentry;
};
/**
* 部分初始化kobject对象。
*/
void kobject_init(struct kobject * kobj)
{
kref_init(&kobj->kref); // 引用置一
INIT_LIST_HEAD(&kobj->entry); // 初始化双向链表
kobj->kset = kset_get(kobj->kset); // 找到其所对应的内核对象集合
}
static inline void kref_init(struct kref *kref)
{
atomic_set(&kref->refcount, 1);
}