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

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)接下来的分析我也不太懂,去看大神的博客。
大神威武

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值