linux内核之sys接口device_add详解
2015-09-26 23:48
597 查看
设备模型之device
1.与device相关的函数有
device_register(struct device *dev);
device_add(struct device *dev);
device_unregister(struct device *dev);
与device attr相关函数:
device_create_file(struct device *dev,struct device_attribute *attr);
device_remove_file(struct device *dev,struct device_attribute *attr);
下面详细分析一下device_add中 在sys接口中创建的kobject与attribute;
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);//获取dev的parent obj
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);//在其parent下创建dev的文件夹
if (error)
goto Error;
/* notify platform of device entry */
if (platform_notify)
platform_notify(dev);
error = device_create_file(dev, &dev_attr_uevent);//在dev的kobject下创建uevent attr;
if (error)
goto attrError;
error = device_add_class_symlinks(dev);//如果dev->class 有值,添加subsystem->class/class_name的链接及添加class/class_name下dev_name->dev的链接
if (error)
goto SymlinkError;
error = device_add_attrs(dev);//添加dev的attr
if (error)
goto AttrsError;
error = bus_add_device(dev);//添加bus->attrs到dev下,并创建subsystem->bus/bus_name的链接
if (error)
goto BusError;
error = dpm_sysfs_add(dev);//添加power group attrs
if (error)
goto DPMError;
device_pm_add(dev);
if (MAJOR(dev->devt)) {
error = device_create_file(dev, &dev_attr_dev);
if (error)
goto DevAttrError;
error = device_create_sys_dev_entry(dev);
if (error)
goto SysEntryError;
devtmpfs_create_node(dev);
}
/* Notify clients of device addition. This call must come
* after dpm_sysfs_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);
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;
SysEntryError:
if (MAJOR(dev->devt))
device_remove_file(dev, &dev_attr_dev);
DevAttrError:
device_pm_remove(dev);
dpm_sysfs_remove(dev);
DPMError:
bus_remove_device(dev);
BusError:
device_remove_attrs(dev);
AttrsError:
device_remove_class_symlinks(dev);
SymlinkError:
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;
}
EXPORT_SYMBOL_GPL(device_add);
1.与device相关的函数有
device_register(struct device *dev);
device_add(struct device *dev);
device_unregister(struct device *dev);
与device attr相关函数:
device_create_file(struct device *dev,struct device_attribute *attr);
device_remove_file(struct device *dev,struct device_attribute *attr);
下面详细分析一下device_add中 在sys接口中创建的kobject与attribute;
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);//获取dev的parent obj
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);//在其parent下创建dev的文件夹
if (error)
goto Error;
/* notify platform of device entry */
if (platform_notify)
platform_notify(dev);
error = device_create_file(dev, &dev_attr_uevent);//在dev的kobject下创建uevent attr;
if (error)
goto attrError;
error = device_add_class_symlinks(dev);//如果dev->class 有值,添加subsystem->class/class_name的链接及添加class/class_name下dev_name->dev的链接
if (error)
goto SymlinkError;
error = device_add_attrs(dev);//添加dev的attr
if (error)
goto AttrsError;
error = bus_add_device(dev);//添加bus->attrs到dev下,并创建subsystem->bus/bus_name的链接
if (error)
goto BusError;
error = dpm_sysfs_add(dev);//添加power group attrs
if (error)
goto DPMError;
device_pm_add(dev);
if (MAJOR(dev->devt)) {
error = device_create_file(dev, &dev_attr_dev);
if (error)
goto DevAttrError;
error = device_create_sys_dev_entry(dev);
if (error)
goto SysEntryError;
devtmpfs_create_node(dev);
}
/* Notify clients of device addition. This call must come
* after dpm_sysfs_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);
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;
SysEntryError:
if (MAJOR(dev->devt))
device_remove_file(dev, &dev_attr_dev);
DevAttrError:
device_pm_remove(dev);
dpm_sysfs_remove(dev);
DPMError:
bus_remove_device(dev);
BusError:
device_remove_attrs(dev);
AttrsError:
device_remove_class_symlinks(dev);
SymlinkError:
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;
}
EXPORT_SYMBOL_GPL(device_add);
相关文章推荐
- linux下面bin,sbin不理解的查阅
- 【2015/9/26】Linux学习日志_Day1 一些终端命令
- Linux中的likely()和unlikely()
- LinuxMint下的Orionode源码安装
- LINUX DHCP学习
- CentOS6.5 corosync+pacemaker+drbd实现mysql高可用
- linux内核设计与实现--内存寻址
- centos 6.5 svn安装和使用
- Linux文件I/O编程(二)lseek函数
- Linux文件I/O编程(二)lseek函数
- Ubuntu Linux中开启MySQL远程访问功能
- Linux常用指令
- 必 备 习 题 集 ( 四 )
- Centos6环境下DNS服务器的搭建
- Linux内核模块指南(前言===>第三章完)。。。翻译完。。。
- 管道和FIFO
- CentOS6.4下Mysql数据库的安装与配置
- 生产场景不同角色linux服务器分区案例分享
- 第十五天:Before -- CMD
- Linux驱动知识点汇总