device 结构与简单注册

来源:互联网 发布:ios蓝牙调试软件 编辑:程序博客网 时间:2024/06/03 21:28
                device注册分析
一.devcie结构体
struct device {
    struct device        *parent;    //父设备指针

    struct device_private    *p;        //很重要

    struct kobject kobj;            //目录与属性管理
    const char        *init_name; /* initial name of the device */
    struct device_type    *type;        //设备类型

    struct semaphore    sem;    /* semaphore to synchronize calls to
                     * its driver.
                     */

    struct bus_type    *bus;        /* type of bus device is on */
    struct device_driver *driver;    /* which driver has allocated this
                       device */
    void        *platform_data;    /* Platform specific data, device
                       core doesn't touch it */
    struct dev_pm_info    power;        //电源管理

#ifdef CONFIG_NUMA
    int        numa_node;    /* NUMA node this device is close to */
#endif
    u64        *dma_mask;    /* dma mask (if dma'able device) */
    u64        coherent_dma_mask;/* Like dma_mask, but for
                         alloc_coherent mappings as
                         not all hardware supports
                         64 bit addresses for consistent
                         allocations such descriptors. */

    struct device_dma_parameters *dma_parms;       //dma设备参数

    struct list_head    dma_pools;    /* dma pools (if dma'ble) */

    struct dma_coherent_mem    *dma_mem; /* internal for coherent mem
                         override */
    /* arch specific additions */
    struct dev_archdata    archdata;    

    dev_t            devt;    /* dev_t, creates the sysfs "dev" */

    spinlock_t        devres_lock;
    struct list_head    devres_head;

    struct klist_node    knode_class;        
    struct class        *class;        
    const struct attribute_group **groups;    /* optional 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_register注册过程分析
int device_register(struct device *dev)
{
    device_initialize(dev);  //设备的初始化
    return device_add(dev);
}

void device_initialize(struct device *dev)
{
    dev->kobj.kset = devices_kset;    //设备集在/sys/devices下
    kobject_init(&dev->kobj, &device_ktype);    //初始化kobj
    INIT_LIST_HEAD(&dev->dma_pools);        
    init_MUTEX(&dev->sem);                //信号量初始化
    spin_lock_init(&dev->devres_lock);
    INIT_LIST_HEAD(&dev->devres_head);        //链表初始化
    device_init_wakeup(dev, 0);            //电源是否可以唤醒初始化
    device_pm_init(dev);                //电源管理初始化
    set_dev_node(dev, -1);                //?
}
int device_add(struct device *dev)
{
    struct device *parent = NULL;
    struct class_interface *class_intf;    
    int error = -EINVAL;

    dev = get_device(dev);    //设备引用计数加1,并返回dev指针
    if (!dev)
        goto done;

    if (!dev->p) {        //如果没有分配则分配并初始化
        error = device_private_init(dev);   
        if (error)
            goto done;
    }

    /*
     * 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);//设置kobj的名
        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);        //设置kobj的父

    /* use parent numa_node */
    if (parent)
        set_dev_node(dev, dev_to_node(parent));

    /* 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);    //建立目录与属性文件
    if (error)
        goto Error;

    /* notify platform of device entry */
    if (platform_notify)
        platform_notify(dev);

    error = device_create_file(dev, &uevent_attr);        //创建uevent属性文件
    if (error)
        goto attrError;

    if (MAJOR(dev->devt)) {
        error = device_create_file(dev, &devt_attr);
        if (error)
            goto ueventattrError;

        error = device_create_sys_dev_entry(dev);
        if (error)
            goto devtattrError;

        devtmpfs_create_node(dev);
    }

    error = device_add_class_symlinks(dev);        //这里不分析class
    if (error)
        goto SymlinkError;
    error = device_add_attrs(dev);    //建立属性文件
    if (error)
        goto AttrsError;
    error = bus_add_device(dev);     //添加到bus中klist_device链表
    if (error)
        goto BusError;
    error = dpm_sysfs_add(dev);    //电源属性文件的建立
    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);

    kobject_uevent(&dev->kobj, KOBJ_ADD);    //发送事件与初始化变量
    bus_probe_device(dev);            //匹配驱动与设备
    if (parent)
        klist_add_tail(&dev->p->knode_parent,
                   &parent->p->klist_children);    //将设备结点添加到klist_children链表中

    if (dev->class) {
        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)
                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;
}

来一个例子吧

0 0
原创粉丝点击