您的位置:首页 > 运维架构 > Linux

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);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: