学习《Linux设备模型浅析之设备篇》笔记(二)
文件/drivers/base/platform.c
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;
}
该源码在《linux设备:初始化》中已经粘贴过,是和devices_init()一起被driver_init(void)调用的,只不过当时没有深挖
文件/drivers/base/core.c
/**
* device_add - 添加device到设备层
* @dev: device.
*
* 这是device_register()的第二层, 不过如果device_initialize()已经被
* 调用过的话,它也可以被单独调用。
*
* 这里通过kobject_add()添加@dev到 kobject 层, 添加它到全局和设备的
* sibling(兄弟) lists,然后把它添加到驱动module的其他相关子系统。
*
* 不要为任何device结构调用该方法或device_register()超过一次。该
* 模型核心不是为那些可以注销掉之后再返回继续使用的设备设计的。
* (在其他部分,很难保证@dev的所有索引都已经释放了) 应该要分配并
* 注册一个新的device结构。
*
* NOTE: 在调用该方法之后绝对不要直接释放 @dev,即使它返回一个
* error! 应该使用put_device()来释放其索引。
*/
int device_add(struct device *dev)
{
struct device *parent = NULL;
struct kobject *kobj;
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;
}
/*
* 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;
}
/* subsystems can specify simple device enumeration */
if (!dev_name(dev) && dev->bus && dev->bus->dev_name)
dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
if (!dev_name(dev)) {
error = -EINVAL;
goto name_error;
}
pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
parent = get_device(dev->parent);
kobj = get_device_parent(dev, parent);
if (kobj)
dev->kobj.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, &dev_attr_uevent);
if (error)
goto attrError;
if (MAJOR(dev->devt)) {
error = device_create_file(dev, &dev_attr_dev);
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);
if (error)
goto SymlinkError;
error = device_add_attrs(dev);
if (error)
goto AttrsError;
error = bus_add_device(dev);
if (error)
goto BusError;
error = dpm_sysfs_add(dev);
if (error)
goto DPMError;
device_pm_add(dev);
/* Notify clients of device addition. 该调用必须在dpm_sysfs_add()
* 之后而在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);
if (dev->class) {
mutex_lock(&dev->class->p->mutex);
/* tie the class to the device */
klist_add_tail(&dev->knode_class, &dev->class->p->klist_devices);
/* notify any interfaces that the device is here */
list_for_each_entry(class_intf, &dev->class->p->interfaces, node)
if (class_intf->add_dev)
class_intf->add_dev(dev, class_intf);
mutex_unlock(&dev->class->p->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, &dev_attr_dev);
ueventattrError:
device_remove_file(dev, &dev_attr_uevent);
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;
}
学习《Linux设备模型浅析之设备篇》笔记(二)相关推荐
- PyTorch学习笔记(二)——回归
PyTorch学习笔记(二)--回归 本文主要是用PyTorch来实现一个简单的回归任务. 编辑器:spyder 1.引入相应的包及生成伪数据 import torch import torch.nn ...
- MATLAB学习笔记——二维和三维绘图
MATLAB学习笔记--二维和三维绘图 近期练习matlab的二维和三维绘图,整理一下,以防忘记. 文章目录 MATLAB学习笔记--二维和三维绘图 一.二维绘图 1.plot命令 2.fplot 命 ...
- 嵌入式系统设计师学习笔记二十八:嵌入式程序设计③——高级程序设计语言
嵌入式系统设计师学习笔记二十八:嵌入式程序设计③--高级程序设计语言 解释程序和编译程序 编译器的工作阶段示意图 语法错误:非法字符,关键字或标识符拼写错误 语法错误:语法结构出错,if--endif ...
- 计算鬼成像学习笔记二:二阶关联函数探究
计算鬼成像学习笔记二:二阶关联函数探究 1 一阶关联函数 2 二阶关联函数 3 二阶关联如何重构物体 4 差分鬼成像关联公式 5 归一化鬼成像关联公式 1 一阶关联函数 一阶关联函数是光场的电场强度之 ...
- qml学习笔记(二):可视化元素基类Item详解(上半场anchors等等)
原博主博客地址:http://blog.csdn.net/qq21497936 本文章博客地址:http://blog.csdn.net/qq21497936/article/details/7851 ...
- [转载]dorado学习笔记(二)
原文地址:dorado学习笔记(二)作者:傻掛 ·isFirst, isLast在什么情况下使用?在遍历dataset的时候会用到 ·dorado执行的顺序,首先由jsp发送请求,调用相关的ViewM ...
- tensorflow学习笔记二——建立一个简单的神经网络拟合二次函数
tensorflow学习笔记二--建立一个简单的神经网络 2016-09-23 16:04 2973人阅读 评论(2) 收藏 举报 分类: tensorflow(4) 目录(?)[+] 本笔记目的 ...
- Scapy学习笔记二
Scapy学习笔记二 Scapy Sniffer的用法: http://blog.csdn.net/qwertyupoiuytr/article/details/54670489 Scapy Snif ...
- Ethernet/IP 学习笔记二
Ethernet/IP 学习笔记二 原文链接:http://wiki.mbalib.com/wiki/Ethernet/IP 1.通信模式 不同于源/目的通信模式,EtherNet/IP 采用生产/消 ...
- Java学习笔记二:数据类型
Java学习笔记二:数据类型 1. 整型:没有小数部分,允许为负数,Java整型分4种:int short long byte 1.1 Int最为常用,一个Int类型变量在内存中占用4个字节,取值范围 ...
最新文章
- spring包自动扫描声明
- MySQL第1天:整体目录
- java的方法什么时候加载,java – JVM什么时候加载类?
- java swt 菜鸟教程_编程基础学习JS的入门教程
- Axios实现异步通信
- 模糊搜索怎么实现_干货 | 你真的了解自己是怎么搜索的吗_01
- webdriver 的三种等待方式
- 互联网日报 | 微信支付启动“8.8智慧生活日”;抖音企业号数量突破400万;苏宁将布局车联网领域...
- java设计与模式_设计模式《JAVA与模式》之状态模式
- 个人电脑 公司电脑 代理_你们想要打造的树莓派电脑,刚发布了官方版:性能更强大,只卖70美元...
- java volatile 原子性_Java并发编程之验证volatile不能保证原子性
- 《番茄工作法图解》一次只做一件事
- Go 爱好者福利,《Go 语言编程之旅》正式开源!
- 订单可视化2实战-生产交付流程(流程再造核心区)
- 从身份证号获取身份证信息
- 上岸重庆邮电大学软件工程学院学硕总结
- 如何给图片加水印,图片加水印怎么加
- iphone手机音频AAC视频H264推流(一) iphone手机推流最佳方案
- Linux学习入门-------------------------VMvare与镜像的安装与配置
- c语言魔王语言上机报告,魔王语言报告(带有完整程序).doc