红联Linux门户
Linux帮助

基于S3C2440平台的linux2.6.22内核版本的设备驱动模型之device_add函数分析

发布时间:2014-08-21 15:19:03来源:红联作者:linux08071151
[code]int device_add(struct device *dev)
{
struct device *parent = NULL;
char *class_name = NULL;
struct class_interface *class_intf;
int error = -EINVAL;

dev = get_device(dev);
if (!dev || !strlen(dev->bus_id))
goto Error;

pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id);

parent = get_device(dev->parent);
error = setup_parent(dev, parent);
if (error)
goto Error;

/* first, register with generic layer. */
kobject_set_name(&dev->kobj, "%s", dev->bus_id);
/*添加kobj到kobj->kset(devices_subsys)中,生成/sys/devices/platform/(dev->kobj.name)目录*/
error = kobject_add(&dev->kobj);
if (error)
goto Error;

/* notify platform of device entry */
if (platform_notify)
platform_notify(dev);

/* notify clients of device entry (new way) */
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->bus_notifier,
BUS_NOTIFY_ADD_DEVICE, dev);

dev->uevent_attr.attr.name = "uevent";
dev->uevent_attr.attr.mode = S_IRUGO | S_IWUSR;
if (dev->driver)
dev->uevent_attr.attr.owner = dev->driver->owner;
dev->uevent_attr.store = store_uevent;
dev->uevent_attr.show = show_uevent;
/*在/sys/devices/platform/(dev->kobj.name)目录下生成名为"uevent"的属性文件,所有注册的dev都会生成这个文件*/
error = device_create_file(dev, &dev->uevent_attr);
goto attrError;
/* 如果有设备号,则生成相应的文件*/
if (MAJOR(dev->devt)) {
struct device_attribute *attr;
attr = kzalloc(sizeof(*attr), GFP_KERNEL);
if (!attr) {
error = -ENOMEM;
goto ueventattrError;
}
attr->attr.name = "dev";
attr->attr.mode = S_IRUGO;
if (dev->driver)
attr->attr.owner = dev->driver->owner;
attr->show = show_dev;
/*如果有,则在dev->kobj.name目录下生成名为"dev"的属性文件,这样udev就能读取该属性文件获得设备号,从而在/dev目录下创建设备节点*/
error = device_create_file(dev, attr);
if (error) {
kfree(attr);
goto ueventattrError;
}

dev->devt_attr = attr;
}

if (dev->class) {
sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj,
"subsystem");
/* If this is not a "fake" compatible device, then create the
* symlink from the class to the device. */
if (dev->kobj.parent != &dev->class->subsys.kobj)
sysfs_create_link(&dev->class->subsys.kobj,
&dev->kobj, dev->bus_id);
if (parent) {
sysfs_create_link(&dev->kobj, &dev->parent->kobj,
"device");
#ifdef CONFIG_SYSFS_DEPRECATED
class_name = make_class_name(dev->class->name,
&dev->kobj);
if (class_name)
sysfs_create_link(&dev->parent->kobj,
&dev->kobj, class_name);
#endif
}
}

if ((error = device_add_attrs(dev)))
goto AttrsError;
if ((error = device_pm_add(dev)))
goto PMError;
/*将device加入到bus的kset中。 在dev->kobj.name目录下生成一个链接文件,其名为"subsystem",
指向其所属的 platform_bus_type的目录/sys/bus/platform,以及在/sys/bus/platform/devices
目录生成一个名为"dev->kobj.name"的链接文件,指向/sys/devices/platform/dev->kobj.name
*/
if ((error = bus_add_device(dev)))
goto BusError;
kobject_uevent(&dev->kobj, KOBJ_ADD);
bus_attach_device(dev);
if (parent)
klist_add_tail(&dev->knode_parent, &parent->klist_children);

if (dev->class) {
down(&dev->class->sem);
/* tie the class to the device */
list_add_tail(&dev->node, &dev->class->devices);

/* notify any interfaces that the device is here */
list_for_each_entry(class_intf, &dev->class->interfaces, node)
if (class_intf->add_dev)
class_intf->add_dev(dev, class_intf);
up(&dev->class->sem);
}
Done:
kfree(class_name);
put_device(dev);
return error;
BusError:
device_pm_remove(dev);
PMError:
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->bus_notifier,
BUS_NOTIFY_DEL_DEVICE, dev);
device_remove_attrs(dev);
AttrsError:
if (dev->devt_attr) {
device_remove_file(dev, dev->devt_attr);
kfree(dev->devt_attr);
}

if (dev->class) {
sysfs_remove_link(&dev->kobj, "subsystem");
/* If this is not a "fake" compatible device, remove the
* symlink from the class to the device. */
if (dev->kobj.parent != &dev->class->subsys.kobj)
sysfs_remove_link(&dev->class->subsys.kobj,
dev->bus_id);
if (parent) {
#ifdef CONFIG_SYSFS_DEPRECATED
char *class_name = make_class_name(dev->class->name,
&dev->kobj);
if (class_name)
sysfs_remove_link(&dev->parent->kobj,
class_name);
kfree(class_name);
#endif
sysfs_remove_link(&dev->kobj, "device");
}
}
ueventattrError:
device_remove_file(dev, &dev->uevent_attr);
attrError:
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
kobject_del(&dev->kobj);
Error:
if (parent)
put_device(parent);
goto Done;
}[/code]
文章评论

共有 2 条评论

  1. linux08071151 于 2014-08-22 11:00:19发表:

    [i=s] 本帖最后由 linux08071151 于 2014-8-22 11:06 编辑 [/i]

    有2处注释需要修改下:
    /*a:if(dev->class) == 0添加kobj到kobj->kset(devices_subsys)中,生成/sys/devices/platform/(dev->kobj.name)目录
    b:if(dev->class) == 1添加kobj到kobj->kset(devices_subsys)中,生成/sys/devices/platform/(dev->class->name)/(dev->kobj.name)目录*/

    /*a:if(dev->class) == 0在/sys/devices/platform/(dev->kobj.name)目录下生成名为"uevent"的属性文件,所有注册的dev都会生成这个文件
    b:if(dev->class) == 1在/sys/devices/platform/(dev->class->name)/(dev->kobj.name)目录下生成"uevent"的属性文件,所有注册的dev都会生成这个文件*/

  2. cnbingu 于 2014-08-22 08:51:22发表:

    深奥