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就创建完成了。我也是学习,所以借鉴了大神的图。
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也创建了。又要借用大神的图了哈哈。我都不好意思了。不过还是感谢大神 博客的教导
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)接下来的分析我也不太懂,去看大神的博客。
大神威武
- Linux内核之platform设备驱动框架的理解
- Linux之platform设备驱动
- 44 linux内核里的platform设备驱动模型
- 【linux设备模型】之platform设备驱动
- Linux platform设备驱动开发框架概述
- Linux总线设备驱动框架的理解
- 关于platform设备驱动框架的总结
- Linux设备驱动模型之platform总线
- LINUX设备驱动之platform总线
- Linux设备驱动模型之platform总线
- Linux驱动之设备模型(9)-platform
- Linux驱动之设备模型(9)-platform
- LINUX设备驱动之platform总线
- Linux驱动之设备模型(9)-platform
- LINUX设备驱动之platform总线
- Linux驱动设备模型之Platform
- Linux驱动之设备模型(9)-platform
- Linux驱动之设备模型(9)-platform
- 从源码角度分析ViewDragHelper
- 实用算法笔记
- 罗技摄像头C270与嵌入式LINUX(linux UVC驱动分析)
- 9 会话技术cookie与session
- javaWEB总结(11):JSP简介及原理
- Linux内核之platform设备驱动框架的理解
- leetcode-37. Sudoku Solver
- Linux Top 命令解析 比较详细
- Vue2.0 开发环境搭建
- 一、C语言的基础
- boost::io_service解读
- Centos 7 PHP7+PHP5.6+NGINX+MYSQL+FTP
- 【9】Hibernate的其他的API
- php获取文件创建时间、修改时间、访问时间