bus总线分析与注册
来源:互联网 发布:阿里云邮件推送资源包 编辑:程序博客网 时间:2024/04/26 03:40
bus总线注册及内部结构
一.下面是bus_type的结构
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); //设备与驱动的匹配函数
int (*uevent)(struct device *dev, struct kobj_uevent_env *env); //事件函数,用于热插拨
int (*probe)(struct device *dev); //探测函数
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; //这个是个非常重要的结构
};
struct bus_type_private { //这个结构体维护了各种链表
struct kset subsys;
struct kset *drivers_kset; //这个保存了/sys/***/driver/集,
应该可以说成一个路径,以后设备与驱动注册会用
struct kset *devices_kset; //这个保存了/sys/***/device/集
struct klist klist_devices; //这个链表管理着这类总线上所有设备
struct klist klist_drivers; //这个链表管理着这类总线上所有驱动
struct blocking_notifier_head bus_notifier; //事件注册与通知链表(以后再分析)
unsigned int drivers_autoprobe:1; //是否允许设备与驱动自动匹配的flag
struct bus_type *bus; //总线类型指针
};
二.函数分析
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_type_private成员bus指向当前bus
bus->p = priv; //bus的bus_type_private指针指向刚分配内存的结构体
BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier); //初始化通知链表
retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name); //设置kobj的名字
if (retval)
goto out;
priv->subsys.kobj.kset = bus_kset; //设置kobj的父目录
priv->subsys.kobj.ktype = &bus_ktype; //kobj的操作方法
priv->drivers_autoprobe = 1; //设置可以自己匹配
retval = kset_register(&priv->subsys); //kset注册,在/sys/建立目录
if (retval)
goto out;
retval = bus_create_file(bus, &bus_attr_uevent); // 在subsys集下建立事件属性文件
if (retval)
goto bus_uevent_fail;
priv->devices_kset = kset_create_and_add("devices", NULL,
&priv->subsys.kobj); //在subsys集下创建device目录
if (!priv->devices_kset) {
retval = -ENOMEM;
goto bus_devices_fail;
}
priv->drivers_kset = kset_create_and_add("drivers", NULL,
&priv->subsys.kobj); //在subsys集下创建driver目录
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); //驱动链表初始化
retval = add_probe_files(bus); //创建(自动)探测属性文件
if (retval)
goto bus_probe_files_fail;
retval = bus_add_attrs(bus); //创建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);
kfree(bus->p);
out:
bus->p = NULL;
return retval;
}
到些,bus_register注册工作已经完成了
下面再看一下其他函数
void bus_unregister(struct bus_type *bus) register的逆过程
{
pr_debug("bus: '%s': unregistering\n", bus->name);
bus_remove_attrs(bus); //bus属性文件的移除
remove_probe_files(bus); //探测文件的移除
kset_unregister(bus->p->drivers_kset); //drivers目录的删除
kset_unregister(bus->p->devices_kset); //devices目录的删除
bus_remove_file(bus, &bus_attr_uevent); //uevent属性文件的移除
kset_unregister(&bus->p->subsys); //sussys集的移除
kfree(bus->p); //释放bus_type_private
bus->p = NULL; //安全操作指向空
}
获得subsys集的指针
struct kset *bus_get_kset(struct bus_type *bus)
{
return &bus->p->subsys;
}
重新扫描事个链表,如果有匹配的设备与驱动则匹配
int bus_rescan_devices(struct bus_type *bus)
{
return bus_for_each_dev(bus, NULL, NULL, bus_rescan_devices_helper);//这里很重要,调用bus_rescan_devices_helper,让设备与驱动得以匹配
}
int bus_for_each_dev(struct bus_type *bus, struct device *start,
void *data, int (*fn)(struct device *, void *))
{
struct klist_iter i; //定义一个遍历结构
struct device *dev;
int error = 0;
if (!bus)
return -EINVAL;
klist_iter_init_node(&bus->p->klist_devices, &i,
(start ? &start->p->knode_bus : NULL)); //初始化一个遍历结构
while ((dev = next_device(&i)) && !error) //遍历所有设备
error = fn(dev, data);
klist_iter_exit(&i); //iter安全处理
return error;
}
static struct device_driver *next_driver(struct klist_iter *i) //获取下一个驱动指针
{
struct klist_node *n = klist_next(i);
struct driver_private *drv_priv;
if (n) {
drv_priv = container_of(n, struct driver_private, knode_bus);
return drv_priv->driver;
}
return NULL;
}
static struct device *next_device(struct klist_iter *i)
{
struct klist_node *n = klist_next(i); //获取下一个结点
struct device *dev = NULL;
struct device_private *dev_prv;
if (n) {
dev_prv = to_device_private_bus(n);//获取下一个p指针,利用container_of(obj, struct device_private, knode_bus)
dev = dev_prv->device; //获取设备指针
}
return dev;
}
struct device *bus_find_device(struct bus_type *bus,
struct device *start, void *data,
int (*match)(struct device *dev, void *data)) //查看设备是否在总线中
{
struct klist_iter i;
struct device *dev;
if (!bus)
return NULL;
klist_iter_init_node(&bus->p->klist_devices, &i,
(start ? &start->p->knode_bus : NULL));
while ((dev = next_device(&i)))
if (match(dev, data) && get_device(dev))
break;
klist_iter_exit(&i);
return dev;
}
struct device *bus_find_device_by_name(struct bus_type *bus,
struct device *start, const char *name) //通过名字查看设备是否在总线,实际调用上面的一个函数
{
return bus_find_device(bus, start, (void *)name, match_name);
}
int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
void *data, int (*fn)(struct device_driver *, void *)) //遍历每一个驱动并匹配设备
{
struct klist_iter i;
struct device_driver *drv;
int error = 0;
if (!bus)
return -EINVAL;
klist_iter_init_node(&bus->p->klist_drivers, &i,
start ? &start->p->knode_bus : NULL);
while ((drv = next_driver(&i)) && !error)
error = fn(drv, data);
klist_iter_exit(&i);
return error;
}
到此bus注册已经完成了
下面附上一个例子
1 #include <linux/module.h>
2 #include <linux/device.h>
3 #include <linux/init.h>
4 #include <linux/types.h>
5
6
7 MODULE_AUTHOR("emperor");
8 MODULE_LICENSE("GPL");
9
10 static char *version = "2014.4.14";
11
12 static int bus_match(struct device *dev, struct device_driver *drv)
13 {
14 return (strcmp(dev->init_name, drv->name) == 0);
15 }
16
17 struct bus_type my_bus = {
18 .name = "bus_test",
19 .match = bus_match,
20 };
21
22 static ssize_t bus_show(struct bus_type *bus, char *buf)
23 {
24 return snprintf(buf, PAGE_SIZE, "%s\n", version);
25 }
26
27 static BUS_ATTR(version, S_IRUGO, bus_show, NULL);
28
29 static int __init bus_init(void)
30 {
31 int ret;
32 ret = bus_register(&my_bus);
33 if(ret)
34 printk(KERN_DEBUG "BUS register is fail\n");
35 bus_create_file(&my_bus, &bus_attr_version);
36 return 0;
小生也是刚刚开始钻研,望各位指出错误,互相进步
一.下面是bus_type的结构
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); //设备与驱动的匹配函数
int (*uevent)(struct device *dev, struct kobj_uevent_env *env); //事件函数,用于热插拨
int (*probe)(struct device *dev); //探测函数
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; //这个是个非常重要的结构
};
struct bus_type_private { //这个结构体维护了各种链表
struct kset subsys;
struct kset *drivers_kset; //这个保存了/sys/***/driver/集,
应该可以说成一个路径,以后设备与驱动注册会用
struct kset *devices_kset; //这个保存了/sys/***/device/集
struct klist klist_devices; //这个链表管理着这类总线上所有设备
struct klist klist_drivers; //这个链表管理着这类总线上所有驱动
struct blocking_notifier_head bus_notifier; //事件注册与通知链表(以后再分析)
unsigned int drivers_autoprobe:1; //是否允许设备与驱动自动匹配的flag
struct bus_type *bus; //总线类型指针
};
二.函数分析
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_type_private成员bus指向当前bus
bus->p = priv; //bus的bus_type_private指针指向刚分配内存的结构体
BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier); //初始化通知链表
retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name); //设置kobj的名字
if (retval)
goto out;
priv->subsys.kobj.kset = bus_kset; //设置kobj的父目录
priv->subsys.kobj.ktype = &bus_ktype; //kobj的操作方法
priv->drivers_autoprobe = 1; //设置可以自己匹配
retval = kset_register(&priv->subsys); //kset注册,在/sys/建立目录
if (retval)
goto out;
retval = bus_create_file(bus, &bus_attr_uevent); // 在subsys集下建立事件属性文件
if (retval)
goto bus_uevent_fail;
priv->devices_kset = kset_create_and_add("devices", NULL,
&priv->subsys.kobj); //在subsys集下创建device目录
if (!priv->devices_kset) {
retval = -ENOMEM;
goto bus_devices_fail;
}
priv->drivers_kset = kset_create_and_add("drivers", NULL,
&priv->subsys.kobj); //在subsys集下创建driver目录
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); //驱动链表初始化
retval = add_probe_files(bus); //创建(自动)探测属性文件
if (retval)
goto bus_probe_files_fail;
retval = bus_add_attrs(bus); //创建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);
kfree(bus->p);
out:
bus->p = NULL;
return retval;
}
到些,bus_register注册工作已经完成了
下面再看一下其他函数
void bus_unregister(struct bus_type *bus) register的逆过程
{
pr_debug("bus: '%s': unregistering\n", bus->name);
bus_remove_attrs(bus); //bus属性文件的移除
remove_probe_files(bus); //探测文件的移除
kset_unregister(bus->p->drivers_kset); //drivers目录的删除
kset_unregister(bus->p->devices_kset); //devices目录的删除
bus_remove_file(bus, &bus_attr_uevent); //uevent属性文件的移除
kset_unregister(&bus->p->subsys); //sussys集的移除
kfree(bus->p); //释放bus_type_private
bus->p = NULL; //安全操作指向空
}
获得subsys集的指针
struct kset *bus_get_kset(struct bus_type *bus)
{
return &bus->p->subsys;
}
重新扫描事个链表,如果有匹配的设备与驱动则匹配
int bus_rescan_devices(struct bus_type *bus)
{
return bus_for_each_dev(bus, NULL, NULL, bus_rescan_devices_helper);//这里很重要,调用bus_rescan_devices_helper,让设备与驱动得以匹配
}
int bus_for_each_dev(struct bus_type *bus, struct device *start,
void *data, int (*fn)(struct device *, void *))
{
struct klist_iter i; //定义一个遍历结构
struct device *dev;
int error = 0;
if (!bus)
return -EINVAL;
klist_iter_init_node(&bus->p->klist_devices, &i,
(start ? &start->p->knode_bus : NULL)); //初始化一个遍历结构
while ((dev = next_device(&i)) && !error) //遍历所有设备
error = fn(dev, data);
klist_iter_exit(&i); //iter安全处理
return error;
}
static struct device_driver *next_driver(struct klist_iter *i) //获取下一个驱动指针
{
struct klist_node *n = klist_next(i);
struct driver_private *drv_priv;
if (n) {
drv_priv = container_of(n, struct driver_private, knode_bus);
return drv_priv->driver;
}
return NULL;
}
static struct device *next_device(struct klist_iter *i)
{
struct klist_node *n = klist_next(i); //获取下一个结点
struct device *dev = NULL;
struct device_private *dev_prv;
if (n) {
dev_prv = to_device_private_bus(n);//获取下一个p指针,利用container_of(obj, struct device_private, knode_bus)
dev = dev_prv->device; //获取设备指针
}
return dev;
}
struct device *bus_find_device(struct bus_type *bus,
struct device *start, void *data,
int (*match)(struct device *dev, void *data)) //查看设备是否在总线中
{
struct klist_iter i;
struct device *dev;
if (!bus)
return NULL;
klist_iter_init_node(&bus->p->klist_devices, &i,
(start ? &start->p->knode_bus : NULL));
while ((dev = next_device(&i)))
if (match(dev, data) && get_device(dev))
break;
klist_iter_exit(&i);
return dev;
}
struct device *bus_find_device_by_name(struct bus_type *bus,
struct device *start, const char *name) //通过名字查看设备是否在总线,实际调用上面的一个函数
{
return bus_find_device(bus, start, (void *)name, match_name);
}
int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
void *data, int (*fn)(struct device_driver *, void *)) //遍历每一个驱动并匹配设备
{
struct klist_iter i;
struct device_driver *drv;
int error = 0;
if (!bus)
return -EINVAL;
klist_iter_init_node(&bus->p->klist_drivers, &i,
start ? &start->p->knode_bus : NULL);
while ((drv = next_driver(&i)) && !error)
error = fn(drv, data);
klist_iter_exit(&i);
return error;
}
到此bus注册已经完成了
下面附上一个例子
1 #include <linux/module.h>
2 #include <linux/device.h>
3 #include <linux/init.h>
4 #include <linux/types.h>
5
6
7 MODULE_AUTHOR("emperor");
8 MODULE_LICENSE("GPL");
9
10 static char *version = "2014.4.14";
11
12 static int bus_match(struct device *dev, struct device_driver *drv)
13 {
14 return (strcmp(dev->init_name, drv->name) == 0);
15 }
16
17 struct bus_type my_bus = {
18 .name = "bus_test",
19 .match = bus_match,
20 };
21
22 static ssize_t bus_show(struct bus_type *bus, char *buf)
23 {
24 return snprintf(buf, PAGE_SIZE, "%s\n", version);
25 }
26
27 static BUS_ATTR(version, S_IRUGO, bus_show, NULL);
28
29 static int __init bus_init(void)
30 {
31 int ret;
32 ret = bus_register(&my_bus);
33 if(ret)
34 printk(KERN_DEBUG "BUS register is fail\n");
35 bus_create_file(&my_bus, &bus_attr_version);
36 return 0;
小生也是刚刚开始钻研,望各位指出错误,互相进步
1 0
- bus总线分析与注册
- BUS HOUND跟USB总线分析仪区别与下载
- linux设备驱动模型之 bus(总线)原理与实例分析
- linux设备驱动模型之 bus(总线)原理与实例分析
- bus - 总线
- 系统启动时在bus系统中注册platform总线
- 系统启动时在bus系统中注册platform总线
- BlueZ5.45 D-Bus总线 GATT API 分析
- Local Bus总线原理
- Local Bus总线原理
- Linux bus总线
- 总线错误(bus err)
- linux bus总线
- linux bus总线
- OttO-bus 事件总线
- TI_DSP总线bus - 2(总线结构与应用以及Bridge的瓶颈)
- TI_DSP总线bus - 3(Bridge,总线连接master与slave表)
- Linux bus总线模型试验
- Struts“No action config found for the specified url.”错误,解决
- mysqldump导入导出mysql数据库
- ORACLE数据库导出(只是结构)
- 百度百科词条中对PX的描述竟是“剧毒
- 文件操作《9》输入错误处理
- bus总线分析与注册
- Persistent Ideal Hash Tries---一种Java实现
- java api学习纪要
- mysql相似于oracle的to_char() to_date()方法
- Mysql Cluster 学习
- 最全面 Nginx 入门教程 + 常用配置解析
- 权限设置
- 和计算机相关的数学~
- oracle 根据周次获取周开始结束日期