Linux内核之platform设备驱动框架的理解

来源:互联网 发布:代谢综合征基因组数据 编辑:程序博客网 时间:2024/06/05 04:07

1.首先明白一点platform的创建是基于bus和device。而且platform的创建分为两步:在devicesmu目录下的创建。和bus目录下的创建。
不多说直接看代码

int __init platform_bus_init(void){    int error;    early_platform_cleanup();    error = device_register(&platform_bus);    if (error)        return error;    error =  bus_register(&platform_bus_type);    if (error)        device_unregister(&platform_bus);    return error;}
struct device platform_bus = {    .init_name  = "platform",};

(1)首先明白__init 这个字段,说明了platform_bus_init函数在内核启动的时候就会被调用执行。我猜测,这个执行的顺序肯定是device和bus先被执行调用,接着platform才会被创建的。(至于device和bus谁先辈调用我也不知道,具体的可以去查看__init 宏定义)
(2)接下来就是early_platform_cleanup,这个函数无关紧要,就是清楚了platform以前的数据。
(3)device_register函数,完成了在device下面的注册和创建了platform目录

int device_register(struct device *dev){    device_initialize(dev);    return device_add(dev);}
void device_initialize(struct device *dev){    //设置platform的容器属于devices_kset(这个变量在device初始化的时候就已经填充了。)    dev->kobj.kset = devices_kset;    //初始化platform的属性和方法    kobject_init(&dev->kobj, &device_ktype);    INIT_LIST_HEAD(&dev->dma_pools);    mutex_init(&dev->mutex);    lockdep_set_novalidate_class(&dev->mutex);    spin_lock_init(&dev->devres_lock);    INIT_LIST_HEAD(&dev->devres_head);    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);    //下面一大堆都是参数校验的    if (!dev)        goto done;    if (!dev->p) {        error = device_private_init(dev);        if (error)            goto done;    }    if (dev->init_name) {        dev_set_name(dev, "%s", dev->init_name);        dev->init_name = NULL;    }    if (!dev_name(dev)) {        error = -EINVAL;        goto name_error;    }    pr_debug("device: '%s': %s\n", dev_name(dev), __func__);    //我看了代码,dev->parent好像是没设置,所以这两句代码也没多大作用。(不知道是不是我分析错了)    parent = get_device(dev->parent);    setup_parent(dev, parent);    /* use parent numa_node */    if (parent)        set_dev_node(dev, dev_to_node(parent));    //重要的是这个函数,下面我会简单的分析一下      error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);    if (error)        goto Error;    /* notify platform of device entry */    if (platform_notify)        platform_notify(dev);    //创建uevent_attr属性,对应的就是/sys/devices/platform/uevent    error = device_create_file(dev, &uevent_attr);    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);    }    //没有设置class所以不会创建符号连接    error = device_add_class_symlinks(dev);    if (error)        goto SymlinkError;    //没有设置文件描述群集,所以不会创建attrs    error = device_add_attrs(dev);    if (error)        goto AttrsError;    //没有设置bus,所以不会被创建    error = bus_add_device(dev);    if (error)        goto BusError;    error = dpm_sysfs_add(dev);    if (error)        goto DPMError;    device_pm_add(dev);    //检测驱动中有无适合的设备进行匹配,但没有设置bus,所以不会进行匹配    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);    //也没有设置class所以也不会进入if语句    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);        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))        devtmpfs_delete_node(dev);    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;}

(2)在kobject_add -> kobject_add_varg -> kobject_add_internal里面的这段代码

    //这里kobj->kset在device_initialize函数被设置了,所以会进入if语句    if (kobj->kset) {        //parent是NULL所以也会进入if语句        if (!parent)            //无则使用父容器为父对象            parent = kobject_get(&kobj->kset->kobj);        kobj_kset_join(kobj);        //设置父对象        kobj->parent = parent;    }

(4)到这里devices目录下的platform就创建完成了。我也是学习,所以借鉴了大神的图。
在devices目录下的platform

2.在bus目录下的创建,因为bus本身的注册函数不怎么懂,我也是学习大神的博客:大神的链接

int bus_register(struct bus_type *bus){    int retval;    struct bus_type_private *priv;    //为在bus下申请一个私自的数据空间    priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);    if (!priv)        return -ENOMEM;     //互相关联    priv->bus = bus;    bus->p = priv;    BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);    //设置bus下面私自创建数据的名字,也就是platform    retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);    if (retval)        goto out;    //设置platform的kset属于bus_set,属性和方法属于bus_ktype    priv->subsys.kobj.kset = bus_kset;    priv->subsys.kobj.ktype = &bus_ktype;    priv->drivers_autoprobe = 1;    //正确设置了platform的父类关系,创建了目录,    retval = kset_register(&priv->subsys);    if (retval)        goto out;    //创建uevent属性文件    retval = bus_create_file(bus, &bus_attr_uevent);    if (retval)        goto bus_uevent_fail;    //priv->subsys.kobj也就是platform,所以就在platform下创建了devices目录    priv->devices_kset = kset_create_and_add("devices", NULL, &priv->subsys.kobj);    if (!priv->devices_kset) {        retval = -ENOMEM;        goto bus_devices_fail;    }    //同理    priv->drivers_kset = kset_create_and_add("drivers", NULL, &priv->subsys.kobj);    if (!priv->drivers_kset) {        retval = -ENOMEM;        goto bus_drivers_fail;    }    klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);    klist_init(&priv->klist_drivers, NULL, NULL);    retval = add_probe_files(bus);    if (retval)        goto bus_probe_files_fail;    retval = bus_add_attrs(bus);    if (retval)        goto bus_attrs_fail;    pr_debug("bus: '%s': registered\n", bus->name);    return 0;bus_attrs_fail:    remove_probe_files(bus);bus_probe_files_fail:    kset_unregister(bus->p->drivers_kset);bus_drivers_fail:    kset_unregister(bus->p->devices_kset);bus_devices_fail:    bus_remove_file(bus, &bus_attr_uevent);bus_uevent_fail:    kset_unregister(&bus->p->subsys);    kfree(bus->p);out:    bus->p = NULL;    return retval;}

(1)到这里bus目录下的platform也创建了。又要借用大神的图了哈哈。我都不好意思了。不过还是感谢大神 博客的教导
bus下的目录结构图

3.platform的注册函数和相关的结构体
struct platform_device {
const char * name;
int id;
struct device dev;
u32 num_resources;
struct resource * resource;

const struct platform_device_id *id_entry;/* arch specific additions */struct pdev_archdata    archdata;

};
int platform_device_register(struct platform_device *pdev)
{
device_initialize(&pdev->dev);
return platform_device_add(pdev);
}
(1)接下来的分析我也不太懂,去看大神的博客。
大神威武

0 0