Linux驱动之bus_register分析

转载:https://blog.csdn.net/u010550992/article/details/50710567
http://www.techbulo.com/1903.html

在这里插入图片描述
上图说明了总线通过两个数据结构:devices_ket和driver_kset来管理注册在此总线上的所有的设备和驱动,为了方便遍历,linux增加了klist_devices和klist_drivers用来实现设备和驱动的遍历
/driver/base/bus.c

struct bus_type mini_bus_type ={
	.name = "mini",
	.match = mini_match
};
 
static int __init test_init(void)
{
	return bus_register(&mini_bus_type);	
}
 
bus_register:工作就是完成bus_type_private的初始化.创建 注册的这条总线需要的目录文件.
             在这条总线目录下创建/device  /driver 目录
             初始化这条总线上的设备链表:struct klist klist_devices;
             初始化这条总线上的驱动链表:struct klist klist_drivers;
             
int bus_register(struct bus_type *bus)
{
	int retval;
	struct bus_type_private *priv;						//是上面mini_bus_type的成员.
 
	priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;
 
	priv->bus = bus;							//struct bus_type_private *p;所指向的内容动态分配.
	bus->p = priv;								//p关联到mini_bus_type
 
	BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
 
	retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);		//kobject对应一个目录,这个目录就是我们看到的总线名字/bus/mini
	if (retval)
		goto out; 
										//bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
	priv->subsys.kobj.kset = bus_kset;					//mini目录在bus下,即/bus/mini:初始化kset的成员kobject,为kset_register()做准备.   
	priv->subsys.kobj.ktype = &bus_ktype;					//static struct kobj_type bus_ktype = {    .sysfs_ops = &bus_sysfs_ops, };    
	priv->drivers_autoprobe = 1;						//设置该标志,	当有driver注册时,会自动匹配devices上的设备并用probe初始化,
										//		当有device注册时,也同样找到driver并会初始化  
										//int bus_add_driver(struct device_driver *drv)
										//	if (drv->bus->p->drivers_autoprobe) { error = driver_attach(drv); }
										  		 											                                   								                                       									    							      
	retval = kset_register(&priv->subsys);					//注册kset,创建目录结构,以及层次关系  生成/bus/mini                               
	if (retval)                                                                                                                           
		goto out;                                 
										//kset_register(&priv->subsys);
											//kobject_add_internal(&k->kobj);
												//error = create_dir(kobj); 
													//error = sysfs_create_dir(kobj);
										//&priv->subsys---->mini_bus_type->p->subsys  		
										//priv->subsys.kobj.kset = bus_kset;
																						                      
	retval = bus_create_file(bus, &bus_attr_uevent);			//mini目录下生成bus_attr_uevent属性文件 
	if (retval)
		goto bus_uevent_fail;
 
	priv->devices_kset = kset_create_and_add("devices", NULL,		//在mini下面创建一个mini/device,是mini这条总线的device的根目录.
						 &priv->subsys.kobj);		//为什么在mini目录下?  (device这个目录:kset->kobj) kset->kobj.parent = &priv->subsys.kobj;
										//在某个目录下:kset->kob.kset =  x    	这个目录在x目录下,这个目录下面“还可有”目录
										//             kobj.parent =     y	这个目录在y目录下,这个目录下面“没有”有目录
	if (!priv->devices_kset) {
		retval = -ENOMEM;
		goto bus_devices_fail;
	}
 
	priv->drivers_kset = kset_create_and_add("drivers", NULL,		//在mini下面创建一个mini/driver,是mini这条总线的driver的根目录.
						 &priv->subsys.kobj);		//struct kset *drivers_kset  指针.  
	if (!priv->drivers_kset) {
		retval = -ENOMEM;
		goto bus_drivers_fail;
	}
 
	klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);	//初始化 mini_bus_type->p->klist_devices  就是初始化device的list_head
	klist_init(&priv->klist_drivers, NULL, NULL);				//					 就是初始化driver的list_head
										//device,driver注册都挂在对应的链表上.
 
	retval = add_probe_files(bus);						//创建文件
	if (retval)
		goto bus_probe_files_fail;
 
	retval = bus_add_attrs(bus);
	if (retval)
		goto bus_attrs_fail;
 
	pr_debug("bus: '%s': registered\n", bus->name);
	return 0;
 
bus_attrs_fail:
	remove_probe_files(bus);
bus_probe_files_fail:
	kset_unregister(bus->p->drivers_kset);
bus_drivers_fail:
	kset_unregister(bus->p->devices_kset);
bus_devices_fail:
	bus_remove_file(bus, &bus_attr_uevent);
bus_uevent_fail:
	kset_unregister(&bus->p->subsys);
out:
	kfree(bus->p);
	bus->p = NULL;
	return retval;
}
 
struct bus_type {
	const char		*name;							//总线名称
	struct bus_attribute	*bus_attrs;						//总线属性(设备节点和这个有关系么?)
	struct device_attribute	*dev_attrs;						//设备属性   
	struct driver_attribute	*drv_attrs;						//驱动属性
 
	int (*match)(struct device *dev, struct device_driver *drv);			//用于匹配总线下的dev和driver
	int (*uevent)(struct device *dev, struct kobj_uevent_env *env);			//用于总线环境变量的添加
	int (*probe)(struct device *dev);						//总线和驱动匹配成功调用,platform不是设备和驱动匹配才调用么?没搞清楚.
	int (*remove)(struct device *dev);
	void (*shutdown)(struct device *dev);						//关机
 
	int (*suspend)(struct device *dev, pm_message_t state);				//挂起
	int (*resume)(struct device *dev);
 
	const struct dev_pm_ops *pm;							//电源管理.
 
	struct bus_type_private *p;							//将bus device sysfs关联起来,怎么关联的不明白呀
};
 
struct bus_type_private {
	struct kset subsys;								//sysfs
	struct kset *drivers_kset;							//bus目录下的 drvier子目录
	struct kset *devices_kset;							//bus目录下的 device子目录
	struct klist klist_devices;							//bus目录下的设备列表
	struct klist klist_drivers;							//bus目录下的驱动列表
	struct blocking_notifier_head bus_notifier;
	unsigned int drivers_autoprobe:1;
	struct bus_type *bus;
};
 
struct bus_attribute {
	struct attribute	attr;
	ssize_t (*show)(struct bus_type *bus, char *buf);
	ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count);
};
 
#define BUS_ATTR(_name, _mode, _show, _store)	\
struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)
 
#define __ATTR(_name,_mode,_show,_store) { \
	.attr = {.name = __stringify(_name), .mode = _mode },	\
	.show	= _show,					\
	.store	= _store,					\
}
 
#define __stringify_1(x...)	#x
#define __stringify(x...)	__stringify_1(x)
 
struct klist {
	spinlock_t		k_lock;
	struct list_head	k_list;
	void			(*get)(struct klist_node *);
	void			(*put)(struct klist_node *);
} __attribute__ ((aligned (sizeof(void *))));

------------------------------------------------------------------------------------

int bus_register(struct bus_type *bus)

{

int retval;

struct bus_type_private *priv;

//分配存储空间

priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);

if (!priv)

return -ENOMEM;

  priv->bus = bus;

     bus->p = priv;

BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);

retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);

if (retval)

goto out;

 

priv->subsys.kobj.kset = bus_kset; 

priv->subsys.kobj.ktype = &bus_ktype;

priv->drivers_autoprobe = 1;

 

retval = kset_register(&priv->subsys);

if (retval)

goto out;

首先,先为struct bus_type的私有区分配空间,然后将其和struct bus_type关联起来.由于struct bus_type也要在sysfs文件中表示一个节点,因此,它也内嵌也一个kset的结构.这就是priv->subsys.

首先,它为这个kset的名称赋值为bus的名称,然后将priv->subsys.kobj.kset指向bus_kset. priv->subsys.kobj.ktype指向bus_ktype;然后调用kset_reqister()将priv->subsys注册.这里涉及到的接口都在之前分析过.注册过后,应该会在bus_kset所表示的目录下创建一个总线名称的目录.并且用户空间的hotplug应该会检测到一个add事件.我们来看一下bus_kset到底指向的是什么:

bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);

从此可以看出.这个bus_kset在sysfs中的结点就是/sys/bus.在这里注册的struct bus_types就会在/sys/bus/下面出现;

bus_create_file()就是在priv->subsys.kobj的这个kobject上建立一个普通属性的文件.这个文件的属性对应在bus_attr_uevent.读写操作对应在priv->subsys.kobj.ktype中.我们到后面才统一分析bus注册时候的文件创建

priv->devices_kset = kset_create_and_add("devices", NULL,

&priv->subsys.kobj);

if (!priv->devices_kset) {

retval = -ENOMEM;

goto bus_devices_fail;

}

 

priv->drivers_kset = kset_create_and_add("drivers", NULL,

&priv->subsys.kobj);

if (!priv->drivers_kset) {

retval = -ENOMEM;

goto bus_drivers_fail;

}

klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);

klist_init(&priv->klist_drivers, NULL, NULL);

这段代码会在bus所在的目录下建立两个目录,分别为devices和drivers.并初始化挂载设备和驱动的链表

retval = add_probe_files(bus);

if (retval)

goto bus_probe_files_fail;

 

retval = bus_add_attrs(bus);

if (retval)

goto bus_attrs_fail;

 

pr_debug("bus: '%s': registered/n", bus->name);

return 0;

在这里,会为bus_attr_drivers_probe, bus_attr_drivers_autoprobe.注册bus_type中的属性建立文件

bus_attrs_fail:

remove_probe_files(bus);

bus_probe_files_fail:

kset_unregister(bus->p->drivers_kset);

bus_drivers_fail:

kset_unregister(bus->p->devices_kset);

bus_devices_fail:

bus_remove_file(bus, &bus_attr_uevent);

bus_uevent_fail:

kset_unregister(&bus->p->subsys);

kfree(bus->p);

out:

return retval;

}

这段代码为出错处理;

struct kset *kset_create_and_add(const char *name,  struct kset_uevent_ops *uevent_ops,

struct kobject *parent_kobj)

{

struct kset *kset;

int error;

//创建一个kset

kset = kset_create(name, uevent_ops, parent_kobj);

if (!kset)

return NULL;

//注册kset

error = kset_register(kset);

if (error)

{

//如果注册失败,释放kset

kfree(kset);

return NULL;

}

return kset;

}

Kset_create()用来创建一个struct kset结构.代码如下:

static struct kset *kset_create(const char *name,

struct kset_uevent_ops *uevent_ops,

struct kobject *parent_kobj)

{

struct kset *kset;

 

kset = kzalloc(sizeof(*kset), GFP_KERNEL);

if (!kset)

return NULL;

kobject_set_name(&kset->kobj, name);

kset->uevent_ops = uevent_ops;

kset->kobj.parent = parent_kobj;

 

kset->kobj.ktype = &kset_ktype;

kset->kobj.kset = NULL;

 

return kset;

}

我们注意,在这里创建kset时.为其内嵌的kobject指定其struct kobj_type ktype结构为kset_ktype.这个结构的定义如下:

static struct kobj_type kset_ktype = {

.sysfs_ops    = &kobj_sysfs_ops,

.release = kset_release,

};

属性文件的读写操作全部都包含在sysfs_ops成员里.kobj_sysfs_ops的定义如下:

struct sysfs_ops kobj_sysfs_ops = {

.show    = kobj_attr_show,

.store   = kobj_attr_store,

};

创建好了kset之后,会调用kset_register().这个函数就是kset操作的核心代码了.如下:

int kset_register(struct kset *k)

{

int err;

 

if (!k)

return -EINVAL;

 

kset_init(k);

err = kobject_add_internal(&k->kobj);

if (err)

return err;

kobject_uevent(&k->kobj, KOBJ_ADD);

return 0;

}

 

void kset_init(struct kset *k)
{
kobject_init_internal(&k->kobj);             //只是对kobj中的成员变量做一些赋值的初始化
INIT_LIST_HEAD(&k->list);
spin_lock_init(&k->list_lock);
}

 

 

static int kobject_add_internal(struct kobject *kobj)

{

int error = 0;

struct kobject *parent;

 

if (!kobj)

return -ENOENT;

//如果kobject的名字为空.退出

if (!kobj->name || !kobj->name[0]) {

pr_debug("kobject: (%p): attempted to be registered with empty "

"name!/n", kobj);

WARN_ON(1);

return -EINVAL;

}

 

//取kobject的父结点

parent = kobject_get(kobj->parent);

//如果kobject的父结点没有指定,就将kset->kobject做为它的父结点

/* join kset if set, use it as parent if we do not already have one */

if (kobj->kset) {

if (!parent)

parent = kobject_get(&kobj->kset->kobj);

kobj_kset_join(kobj);

kobj->parent = parent;

}

//调试用

pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'/n",

kobject_name(kobj), kobj, __FUNCTION__,

parent ? kobject_name(parent) : "<NULL>",

kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");

//在sysfs中创建kobject的相关元素

error = create_dir(kobj);

if (error) {

//v如果创建失败。减少相关的引用计数

kobj_kset_leave(kobj);

kobject_put(parent);

kobj->parent = NULL;

 

/* be noisy on error issues */

if (error == -EEXIST)

printk(KERN_ERR "%s failed for %s with "

"-EEXIST, don't try to register things with "

"the same name in the same directory./n",

__FUNCTION__, kobject_name(kobj));

else

printk(KERN_ERR "%s failed for %s (%d)/n",

__FUNCTION__, kobject_name(kobj), error);

dump_stack();

} else

//如果创建成功。将state_in_sysfs建为1。表示该object已经在sysfs中了

kobj->state_in_sysfs = 1;

 

return error;

}

这段代码比较简单,它主要完成kobject父结点的判断和选定,然后再调用create_dir()在sysfs创建相关信息。该函数代码如下:

static int create_dir(struct kobject *kobj)

{

int error = 0;

if (kobject_name(kobj)) {

//为kobject创建目录

error = sysfs_create_dir(kobj);

if (!error) {

//为kobject->ktype中的属性创建文件

error = populate_dir(kobj);

if (error)

sysfs_remove_dir(kobj);

}

}

return error;

}

 

int sysfs_create_dir(struct kobject * kobj)

{

struct sysfs_dirent *parent_sd, *sd;

int error = 0;

 

BUG_ON(!kobj);

/*如果kobject的parnet存在。就在目录点的目录下创建这个目录。如果没有父结点不存在,就在/sys下面创建结点。*/

if (kobj->parent)

parent_sd = kobj->parent->sd;

else

parent_sd = &sysfs_root;

 

//在sysfs中创建目录

//create_dir()就是在sysfs中创建目录的接口,在之前已经详细分析过了

error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);

if (!error)

kobj->sd = sd;

return error;

}

接着看为kobject->ktype中的属性创建文件。这是在populate_dir()中完成的。代码如下:

static int populate_dir(struct kobject *kobj)

{

struct kobj_type *t = get_ktype(kobj);

struct attribute *attr;

int error = 0;

int i;

 

if (t && t->default_attrs) {

for (i = 0; (attr = t->default_attrs[i]) != NULL; i++) {

error = sysfs_create_file(kobj, attr);

if (error)

break;

}

}

return error;

}

这段代码比较简单。它遍历ktype中的属性。然后为其建立文件。请注意:文件的操作最后都会回溯到ktype->sysfs_ops的show和store这两个函数中.

假如对于上面的bus_register()函数传入的参数为:

struct bus_type ldd_bus_type = {
.name = "ldd",
.match = ldd_match,
.hotplug  = ldd_hotplug,
};
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值