博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
device_register
阅读量:4225 次
发布时间:2019-05-26

本文共 6310 字,大约阅读时间需要 21 分钟。

原文地址:我对linux的理解之device_register 作者:amingriyue
------------------------------------------
本文系本站原创,欢迎转载!
转载请注明出处:amingriyue.blog.chinaunix.net
------------------------------------------
/** * device_register - register a device with the system. * @dev: pointer to the device structure * * This happens in two clean steps - initialize the device * and add it to the system. The two steps can be called * separately, but this is the easiest and most common. * I.e. you should only call the two helpers separately if * have a clearly defined need to use and refcount the device * before it is added to the hierarchy. * * NOTE: _Never_ directly free @dev after calling this function, even * if it returned an error! Always use put_device() to give up the * reference initialized in this function instead. */int device_register(struct device *dev){    device_initialize(dev);  //初始化dev,见第1部分分析    return device_add(dev);  //添加设备,这是device_register的主要工作,见第2部分分析}
函数定义很简洁,第一步初始化dev,第二步添加设备。我们也分两部分进行分析:
1,device_initialize()
void device_initialize(struct device *dev){    dev->kobj.kset = devices_kset;  //devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL),即devices_kset代表了/sys/devices/    kobject_init(&dev->kobj, &device_ktype);  //初始化dev的kobj,这个函数在driver_register中分析过了    INIT_LIST_HEAD(&dev->dma_pools);  //初始化dev的内存池的列表    init_MUTEX(&dev->sem);  //初始化信号量    spin_lock_init(&dev->devres_lock); //初始化自旋锁    INIT_LIST_HEAD(&dev->devres_head); //初始化队列头    device_init_wakeup(dev, 0);  //由其定义知初始化dev->power.can_wakeup = dev->power.should_wakeup = 0;    device_pm_init(dev);  //初始化dev->power.status = DPM_ON;    set_dev_node(dev, -1); //如果配置了numa,设置dev->numa_node = -1;  numa是非统一内存访问架构,一般用于服务器中,所以一般嵌入式中不使用。}
这个dev的初始化主要是设置dev结构中的各个变量等以及对kobj的相关操作。
2,device_add()
int device_add(struct device *dev){    struct device *parent = NULL;    struct class_interface *class_intf;    int error = -EINVAL;    dev = get_device(dev); //主要是增加dev->kobj->kref的引用    if (!dev)        goto done;    dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL); //这里p是dev中的device_private结构,跟驱动的driver_private相似    if (!dev->p) {        error = -ENOMEM;        goto done;    }    dev->p->device = dev; //将dev赋值给p的device保存    klist_init(&dev->p->klist_children, klist_children_get,               klist_children_put);  //初始化p的klist_children    /*     * for statically allocated devices, which should all be converted     * some day, we need to initialize the name. We prevent reading back     * the name, and force the use of dev_name()     */    if (dev->init_name) {        dev_set_name(dev, "%s", dev->init_name);        dev->init_name = NULL;    }    if (!dev_name(dev))        goto name_error;    pr_debug("device: '%s': %s\n", dev_name(dev), __func__);    parent = get_device(dev->parent); //得到父设备    setup_parent(dev, parent);    /* use parent numa_node */    if (parent)        set_dev_node(dev, dev_to_node(parent)); //不使用numa    /* first, register with generic layer. */    /* we require the name to be set before, and pass NULL */    error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);  //这个函数在driver_register中分析过了,主要将kobj添加到sys的层次中    if (error)        goto Error;    /* notify platform of device entry */    if (platform_notify)        platform_notify(dev);    error = device_create_file(dev, &uevent_attr);  //在driver_register中已经分析,主要是在/sys/devices/.../中添加dev的uevent属性文件    if (error)        goto attrError;    if (MAJOR(dev->devt)) {        error = device_create_file(dev, &devt_attr);  //主要是在sys/devices/...中添加dev属性文件        if (error)            goto ueventattrError;        error = device_create_sys_dev_entry(dev); //在/sys/dev/char/或者/sys/dev/block/创建devt的属性的连接文件,形如10:45,由主设备号和次设备号构成,指向/sys/devices/.../的具体设备目录,该链接文件只具备读属性,显示主设备号:次设备号,如10:45,用户空间udev相应uevent事件时,将根据设备号在/dev下创建节点文件        if (error)            goto devtattrError;    }    error = device_add_class_symlinks(dev); //相互创建dev和class之间的链接文件    if (error)        goto SymlinkError;    error = device_add_attrs(dev); //添加设备属性文件    if (error)        goto AttrsError;    error = bus_add_device(dev); //将设备添加到bus上,创建subsystem链接文件,链接class下的具体的子系统文件夹    if (error)        goto BusError;    error = dpm_sysfs_add(dev); //添加设备的电源管理属性,截止这里,我们的/sys/devices/.../具体设备目录下至少生成有以下四个属性文件:uevent,dev,subsystem,power,你找到了吗?    if (error)        goto DPMError;    device_pm_add(dev); //添加设备到激活设备列表中,用于电源管理    /* Notify clients of device addition.  This call must come     * after dpm_sysf_add() and before kobject_uevent().     */    if (dev->bus)        blocking_notifier_call_chain(&dev->bus->p->bus_notifier,                                     BUS_NOTIFY_ADD_DEVICE, dev);//执行bus通知链上的注册函数,由设备注册上来    kobject_uevent(&dev->kobj, KOBJ_ADD); //产生一个KOBJ_ADD的uevent事件,通过netlink机制和用户空间通信,这个driver_register中已经分析过了    bus_probe_device(dev); //去bus上找dev对应的drv,主要执行__device_attach,主要进行match,sys_add,执行probe函数和绑定等操作    if (parent)        klist_add_tail(&dev->p->knode_parent,                       &parent->p->klist_children); //把设备添加到父设备的children列表中    if (dev->class) {  //如果改dev有所属类,则将dev的添加到类的设备列表里面        mutex_lock(&dev->class->p->class_mutex);        /* tie the class to the device */        klist_add_tail(&dev->knode_class,                   &dev->class->p->class_devices);        /* notify any interfaces that the device is here */        list_for_each_entry(class_intf,                    &dev->class->p->class_interfaces, node)            if (class_intf->add_dev) //执行改dev的class_intf->add_dev(),这个有个好处,就是只有设备匹配注册成功了,才进行其它的注册工作(如字符设备的注册,生成/dev/***节点文件)以及部分初始化工作。                class_intf->add_dev(dev, class_intf);        mutex_unlock(&dev->class->p->class_mutex);    }done:    put_device(dev);    return error; DPMError:    bus_remove_device(dev); BusError:    device_remove_attrs(dev); AttrsError:    device_remove_class_symlinks(dev); SymlinkError:    if (MAJOR(dev->devt))        device_remove_sys_dev_entry(dev); devtattrError:    if (MAJOR(dev->devt))        device_remove_file(dev, &devt_attr); ueventattrError:    device_remove_file(dev, &uevent_attr); attrError:    kobject_uevent(&dev->kobj, KOBJ_REMOVE);    kobject_del(&dev->kobj); Error:    cleanup_device_parent(dev);    if (parent)        put_device(parent);name_error:    kfree(dev->p);    dev->p = NULL;    goto done;}
这部分是device_register的主要工作,我们这里就不在详细分析了,相信有了driver_register分析的基础,这部分分析工作应该会变得很轻松~
你可能感兴趣的文章
paramiko——一个专门为Linux设计的模块
查看>>
一个有趣的python项目---一个好玩的网站
查看>>
git常用命令总结
查看>>
Protobuf了解一下?
查看>>
超越Selenium的存在---Pyppeteer
查看>>
复仇者联盟4:终局之战剧透
查看>>
Msgpack有没有兴趣了解一下?
查看>>
探索一家神秘的公司
查看>>
PDF转Word完全免费?这么好的事情我怎么不知道????
查看>>
数据解读---B站火过蔡徐坤的“鬼畜“区巨头们
查看>>
Squid代理服务器搭建亿级爬虫IP代理池
查看>>
JupyterNotebook‘s Magic
查看>>
在Linux 上部署Jenkins和项目
查看>>
Python+requests+unittest+excel实现接口自动化测试框架
查看>>
那些年我们听过的互联网公司的套路?
查看>>
谈谈python里面那些高级函数
查看>>
40行代码带你免费看《海贼王-和之国》篇章
查看>>
搭建炫酷的服务器监控平台
查看>>
垃圾分类:人机搭配,干活不累
查看>>
Nginx
查看>>