总结:挂载文件到device下(具体目录可能各有不同),如果是class,则有几个相互的链接。sysfs跟ramfs不同的是,sysfs具体操作,文件建立,生成链接,都用struct kobject,而不是直接的应用dentry。最最简单的理解,就是把一个kobject挂到devices_subsys的kset上。
/**
* device_register- register a device with the system.
* @dev: pointerto the device structure
*
* Thishappens in two clean steps -initialize the device
* andadd it to the system. The two steps can be called
* separately,but this is the easiest and most common.
* I.e.you should only call the two helpers separately if
* havea clearly defined need to use and refcount the device
* beforeit is added to the hierarchy.
*/
intdevice_register(struct device *dev)
{
device_initialize(dev); //初始化设备
//dev.kobj.kset=device_sbusys.kset
returndevice_add(dev);
}
按照注释里说明的那样,分两步,一是初始化,二是添加
第一部分:
/**
* device_initialize- init device structure.
* @dev: device.
*
* Thisprepares the device for use by other layers,
* includingadding it to the device hierarchy.
* Itis the first half of device_register(), if called by
* that,though it can also be called separately, so one
* mayuse @dev's fields (e.g. the refcount).
*/
voiddevice_initialize(struct device *dev)
这个函数里有一行代码kobj_set_kset_s(dev, devices_subsys);它的作用就是dev.kobj.kset=device_sbusys.kset //对象的kset指向devices_subsys的kset
klist_init(&dev->klist_children,klist_children_get,
klist_children_put);maybe也可以适当关注一下
第二部分:
/**
* device_add- add device to device hierarchy.
* @dev: device.
*
* Thisis part 2 of device_register(), though may be called
* separately_iff_ device_initialize() has been called separately.
*
* This adds it to the kobject hierarchy via kobject_add(), addsit
* tothe global and sibling lists for the device,
* then adds it to the other relevant subsystems of the driver model.
*/
intdevice_add(struct device *dev)
这个函数很长很核心,且慢慢分析:
1、
parent =get_device(dev->parent);
error =setup_parent(dev,parent); //如果class存在且parent为NULL,则获取为class的virtual,
//是在/sys/device/virtual
//设置的是dev->kobj.parent,而非parent
//如果parent存在,则为parent。
这两行企图去获得parent,然后dev->kobj.parent指向这个父节点。这个在后面add,也就是挂载的时候很需要,
如果是NULL,也没关系,慢慢来
2、
/* first, registerwith generic layer. */
kobject_set_name(&dev->kobj,"%s",dev->bus_id); //名字
error =kobject_add(&dev->kobj); //先dentry\inode\sd,一个都不少,然后父节点呢,是device
//dev->kobj->dentry=dentry
//然后父节点有张表,来存放新添加的obj
//这里其实已经挂载上去了。比如platform已经在device下面了
//dev->kobj->kset=device,you know?
这两行代码就是挂载,kobject_add在subsystem_register中已经有所分析。
最重要的是:
if (kobj->kset) { //前提是kset要存在,如果是device,fs的subsystem 这项应该不存在
spin_lock(&kobj->kset->list_lock);
if (!parent)
parent = kobject_get(&kobj->kset->kobj); //如果父节点不存在,kset的对象就是父节点
//如platform_type_bus的kobj->kset->kobj 就是device_subsys->kset->kobj
//其实可以这么理解,如果父节点也没,kset也没,就直接挂在sys下
//如果有父节点就挂在父节点下,如果有kset就挂在kset下
list_add_tail(&kobj->entry,&kobj->kset->list); //将kobj->entry加到kset的节点,需要信息是不是遍历这张表
spin_unlock(&kobj->kset->list_lock);
}(kobject_shadow_add节选)
即使没有父节点,也会进入这里,进入这里意味着什么呢?结合初始化时候:dev.kobj.kset=device_sbusys.kset
也就是说即使没有父节点,那么父节点就是device_sbusys.kset,也就是说,如果初始父节点是NULL的话,那么就挂在device下,也就是sys/device这个目录下。
接下来跟前面subsystem中的kobject_add没什么差异了
3、
dev->uevent_attr.attr.name= "uevent";
dev->uevent_attr.attr.mode= S_IWUSR;
if(dev->driver)
dev->uevent_attr.attr.owner= dev->driver->owner;
dev->uevent_attr.store= store_uevent;
error= device_create_file(dev,&dev->uevent_attr); //生成文件挂载在设备目录上面
if(error)
gotoattrError;
这几行代码很容易理解,设置一个属性名问uevent的,然后将它挂载到上面挂载上的文件上去。
接下来有类似的代码,比如说如果是设备文件,就设置dev属性。
4、
if (dev->class) {
sysfs_create_link(&dev->kobj, &dev->class->subsys.kset.kobj,
"subsystem"); //将/sys/class/xxx挂至当前对象下
//如/sys/class/tty挂至/sys/device/virtual/tty/ttyS0/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.kset.kobj)
sysfs_create_link(&dev->class->subsys.kset.kobj,
&dev->kobj, dev->bus_id); //将当前对象挂载到class下
///sys/device/virtual/tty/ttyS0挂到/sys/class/tty
if (parent) {
sysfs_create_link(&dev->kobj, &dev->parent->kobj,
"device"); //将父对象挂载到当前对象的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
}
这段代码很有趣,如果设备有class,那么还要创建一个链接。上面的代码1里已经说了,如果有class且parent为NULL的话,那么dev->kobj是挂载device/virtual下的。
下面的图片很直观,创建是device/virtual/tty/ttyS0中的subsystem指向了class/tty
然后创建class/tty/ttyS0指向device/virtual/tty/ttyS0
5、
后面的代码更像是在善后,前面大的基础已经打好了,后面的一些私有属性,该添加的添加。
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); //将当前节点添加至class设备链表中、
//如ttys0添加到tty_class
/* 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);
}
dev->knode_parent添加到parent->klist_children的链表中。
这样方便管理查找