您的位置:首页 > 运维架构 > Linux

Linux内核之Devices创建过程解 4000 析

2016-11-25 19:55 162 查看
内核版本:2.6.35.7

声明:一部分是我自己整理的,大多数都是参考别人文章整理的。也感谢那些经常发文章教导的大神们。废话不说,进入正题。

参考文章链接

Device的创建是基于kobject和kset。

参考文章链接

1.要明白Device的创建过程,首先要知道它相关的结构体

struct device {
struct device       *parent;                //指向父节点的指针

struct device_private   *p;

struct kobject kobj;                        //把它联系到sysfs中
const char      *init_name;                 //设备的名字
struct device_type  *type;

struct mutex        mutex;

struct bus_type *bus;                       //对设备所在总线的指针
struct device_driver *driver;               //对设备所用驱动的指针
void        *platform_data;
struct dev_pm_info  power;
u64     *dma_mask;
u64     coherent_dma_mask;
struct device_dma_parameters *dma_parms;

struct list_head    dma_pools;

struct dma_coherent_mem *dma_mem;
struct dev_archdata archdata;
dev_t           devt;                       //设备号

spinlock_t      devres_lock;
struct list_head    devres_head;            //表示设备的资源

struct klist_node   knode_class;            //被连入class链表所用的指针
struct class        *class;                 //指向类的指针
const struct attribute_group **groups;      //设备属性的集合
void    (*release)(struct device *dev);     //设备释放所调用的函数
};

struct device_private {
struct klist klist_children;                //子设备的链表
struct klist_node knode_parent;             //连接入父设备链表所用节点
struct klist_node knode_driver;             //连接入驱动设备链表所用节点
struct klist_node knode_bus;                //连接入总线所用节点
void *driver_data;                          //存放驱动信息
struct device *device;                      //指向device_private所属的device
};


2.Device的注册

int __init devices_init(void)
{
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
if (!devices_kset)
return -ENOMEM;
dev_kobj = kobject_create_and_add("dev", NULL);
if (!dev_kobj)
goto dev_kobj_err;
sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
if (!sysfs_dev_block_kobj)
goto block_kobj_err;
sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
if (!sysfs_dev_char_kobj)
goto char_kobj_err;

return 0;

char_kobj_err:
kobject_put(sysfs_dev_block_kobj);
block_kobj_err:
kobject_put(dev_kobj);
dev_kobj_err:
kset_unregister(devices_kset);
return -ENOMEM;
}


(1)从kset_create_and_add函数入手(Tab键表示函数的层级关系)

kset_create_and_add(“devices”, &device_uevent_ops, NULL);

kset_create(devices, device_uevent_ops, NULL);//创建一个容器

kobject_set_name(&kset->kobj, devices);//设置容器名字

kset_register(kset);//注册要创建的容器

(2)上代码关于kobject_set_name函数和kset_register函数

static struct kset *kset_create(const char *name,
const struct kset_uevent_ops *uevent_ops,
struct kobject *parent_kobj)
{
struct kset *kset;
int retval;
//为要创建的容器分配内存空间
kset = kzalloc(sizeof(*kset), GFP_KERNEL);
if (!kset)
return NULL;
//设置容器的名字,也就是devices
retval = kobject_set_name(&kset->kobj, name);
if (retval) {
kfree(kset);
return NULL;
}
//绑定uevent_ops,具体我也不知道,毕竟我还是学生,我看了很多文章都没提及
kset->uevent_ops = uevent_ops;
//绑定对象的父类,这里是NULL
kset->kobj.parent = parent_kobj;

//绑定操作这个容器的方法和属性
kset->kobj.ktype = &kset_ktype;
kset->kobj.kset = NULL;
return kset;
}


int kset_register(struct kset *k)

{

int err;

if (!k)

return -EINVAL;

//初始化我们创建好的devices,具体的可以去看我参考的第二篇文章
kset_init(k);
err = kobject_add_internal(&k->kobj);
if (err)
return err;
kobject_uevent(&k->kobj, KOBJ_ADD);
return 0;


}

kset_init大概就做了一些:初始化devices链表,初始化了链表锁

kobject_add_internal是比较重要的一个函数

static int kobject_add_internal(struct kobject *kobj)
{
int error = 0;
struct kobject *parent;

if (!kobj)
return -ENOENT;

if (!kobj->name || !kobj->name[0]) {
WARN(1, "kobject: (%p): attempted to be registered with empty "
"name!\n", kobj);
return -EINVAL;
}

parent = kobject_get(kobj->parent);
//因为在kset_create中设置了kset->kobj.kset = NULL;
//所以下面这个if语句不会进去
if (kobj->kset) {
if (!parent)
parent = kobject_get(&kobj->kset->kobj);
kobj_kset_join(kobj);
kobj->parent = parent;
}

pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
kobject_name(kobj), kobj, __func__,
parent ? kobject_name(parent) : "<NULL>",
kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
//接下来就创建了目录,具体我也没看懂,因为看函数名字就知道创建了这个device目录,能力有限。请见谅
error = create_dir(kobj);
if (error) {
kobj_kset_leave(kobj);
kobject_put(parent);
kobj->parent = NULL;

/* be noisy on error issues */
if (error == -EEXIST)
printk(KERN_ERR "%s failed for %s with "
"-EEXIST, don't try to register things with "
"the same name in the same directory.\n",
__func__, kobject_name(kobj));
else
printk(KERN_ERR "%s failed for %s (%d)\n",
__func__, kobject_name(kobj), error);
dump_stack();
} else
kobj->state_in_sysfs = 1;

return error;
}


(3)至此device目录也就建立起来了,能力有限也只能分析到这。转载一张大神的图片。



2.devices_init函数里面的接下来几个函数

//创建一个dev的目录
dev_kobj = kobject_create_and_add("dev", NULL);
if (!dev_kobj)
goto dev_kobj_err;
//在dev目录下创建block
sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
if (!sysfs_dev_block_kobj)
goto block_kobj_err;
//在dev目录下创建char
sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
if (!sysfs_dev_char_kobj)
goto char_kobj_err;


跟上面的注册大同小异
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux kernel struct 结构