Linux设备驱动模型-Bus
前言
数据结构
struct bus_type {const char *name;const char *dev_name;struct device *dev_root;struct device_attribute *dev_attrs; /* use dev_groups instead */const struct attribute_group **bus_groups;const struct attribute_group **dev_groups;const struct attribute_group **drv_groups;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 (*online)(struct device *dev);int (*offline)(struct device *dev);int (*suspend)(struct device *dev, pm_message_t state);int (*resume)(struct device *dev);const struct dev_pm_ops *pm;const struct iommu_ops *iommu_ops;struct subsys_private *p;struct lock_class_key lock_key;
};
.name: 总线的名称,比如i2c, spi
struct subsys_private {struct kset subsys;struct kset *devices_kset;struct list_head interfaces;struct mutex mutex;struct kset *drivers_kset;struct klist klist_devices;struct klist klist_drivers;struct blocking_notifier_head bus_notifier;unsigned int drivers_autoprobe:1;struct bus_type *bus;struct kset glue_dirs;struct class *class;
};
.subsys: 用来表示bus所在的子系统,系统中所有注册的bus都将指向bus_kset。
BUS相关的函数
- buses_init(创建bus/system集合)
int __init buses_init(void)
{bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);if (!bus_kset)return -ENOMEM;system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj);if (!system_kset)return -ENOMEM;return 0;
}
通过上述的操作将在sysfs下创建了一个名字为"bus"的目录,同时也会在/sys/devices/下创建一个名字为"system"的目录。
static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)
{struct kobj_type *ktype = get_ktype(kobj);if (ktype == &bus_ktype)return 1;return 0;
}static const struct kset_uevent_ops bus_uevent_ops = {.filter = bus_uevent_filter,
};
在bus_uevent_ops中只实现了filter函数。此函数只要是判断发生状态的kobj对象类型是不是总线类型,不是就不会上报该事件的。
- bus_register(注册一个总线到系统中)
int bus_register(struct bus_type *bus)
{int retval;struct subsys_private *priv;struct lock_class_key *key = &bus->lock_key;priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL); //分配subsys_private结构体if (!priv)return -ENOMEM;priv->bus = bus; //设置bus指针bus->p = priv; //设置bus->p指针BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier); //初始化bus通知链retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name); //设置该bus的名字,体现在/sys/bus/下if (retval)goto out;priv->subsys.kobj.kset = bus_kset; //设置该bus所属的kset, 以及ktypepriv->subsys.kobj.ktype = &bus_ktype;priv->drivers_autoprobe = 1;retval = kset_register(&priv->subsys); //注册该kset到系统中,表现在/sys/bus下if (retval)goto out;retval = bus_create_file(bus, &bus_attr_uevent); //创建该bus的uevent属性if (retval)goto bus_uevent_fail;priv->devices_kset = kset_create_and_add("devices", NULL, &priv->subsys.kobj); //在该bus下创建devices目录if (!priv->devices_kset) {retval = -ENOMEM;goto bus_devices_fail;}priv->drivers_kset = kset_create_and_add("drivers", NULL,&priv->subsys.kobj); //在该bus下创建drivers目录if (!priv->drivers_kset) {retval = -ENOMEM;goto bus_drivers_fail;}INIT_LIST_HEAD(&priv->interfaces); //初始化interface, mutex, klist_devices, klist_drivers__mutex_init(&priv->mutex, "subsys mutex", key);klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);klist_init(&priv->klist_drivers, NULL, NULL);retval = add_probe_files(bus); //创建bus的probe属性if (retval)goto bus_probe_files_fail;retval = bus_add_groups(bus, bus->bus_groups); //创建bus的属性if (retval)goto bus_groups_fail;pr_debug("bus: '%s': registered\n", bus->name);return 0;
}
比如常见的通过bus_register创建一个i2c总线,就会在/sys/bus/下创建i2c目录, 以及devices目录, driver目录, 以及probe属性, uevent属性。
root@test:/sys/bus/i2c # ls -l
drwxr-xr-x root root 2012-01-01 08:17 devices
drwxr-xr-x root root 2012-01-01 08:17 drivers
-rw-r--r-- root root 4096 2012-01-01 08:17 drivers_autoprobe
--w------- root root 4096 2012-01-01 08:17 drivers_probe
--w------- root root 4096 2012-01-01 08:17 uevent
而在devices下就是该i2c-bus下所有的设备,drivers下就是i2c-bus下所有去的驱动。
- subsys_register(注册一个子系统)
static int subsys_register(struct bus_type *subsys,const struct attribute_group **groups,struct kobject *parent_of_root)
{struct device *dev;int err;err = bus_register(subsys); //注册一个总线if (err < 0)return err;dev = kzalloc(sizeof(struct device), GFP_KERNEL); //分配一个device结构,然后设置名字if (!dev) {err = -ENOMEM;goto err_dev;}err = dev_set_name(dev, "%s", subsys->name);if (err < 0)goto err_name;dev->kobj.parent = parent_of_root; //设置该device的parent,通常都是在buses_init中的system_ksetdev->groups = groups; //表现在sys中就是在/sys/devices/system下新建一个subsys->name的目录dev->release = system_root_device_release;err = device_register(dev); //注册该设备if (err < 0) goto err_dev_reg;subsys->dev_root = dev;return 0;
}
- subsys_system_register(/sys/devices/system/下注册一个子系统)
int subsys_system_register(struct bus_type *subsys,const struct attribute_group **groups)
{return subsys_register(subsys, groups, &system_kset->kobj);
}
该函数将会调用上面的subsys_register函数。举例:
static int __init clockevents_init_sysfs(void)
{int err = subsys_system_register(&clockevents_subsys, NULL);if (!err)err = tick_init_sysfs();return err;
}
struct bus_type clockevents_subsys = {.name = "clockevents",.dev_name = "clockevent",
};
这样的话,就会在/sys/devices/system下创建一个名字为"clockevent"设备,在/sys/bus/下创建一个名字为“clockevents”的总线
root@test:/sys/bus/clockevents # ls
devices
drivers
drivers_autoprobe
drivers_probe
uevent
root@test:/sys/devices/system/clockevents # ls -l
drwxr-xr-x root root 2012-01-01 08:00 broadcast
drwxr-xr-x root root 2012-01-01 08:00 clockevent0
drwxr-xr-x root root 2012-01-01 08:00 clockevent1
drwxr-xr-x root root 2012-01-01 08:00 clockevent2
drwxr-xr-x root root 2012-01-01 08:00 clockevent3
drwxr-xr-x root root 2012-01-01 08:00 clockevent4
drwxr-xr-x root root 2012-01-01 08:00 clockevent5
drwxr-xr-x root root 2012-01-01 08:00 clockevent6
drwxr-xr-x root root 2012-01-01 08:00 clockevent7
drwxr-xr-x root root 2012-01-01 08:00 power
-rw-r--r-- root root 4096 2012-01-01 08:00 uevent
不过根据该函数的注释“Do not use this interface for anything new, it exists for compatibility with bad ideas only.” 意思是不在建议使用该函数了。
- subsys_virtual_register(在/sys/devices/virtual/下创建一个子系统)
int subsys_virtual_register(struct bus_type *subsys,const struct attribute_group **groups)
{struct kobject *virtual_dir;virtual_dir = virtual_device_parent(NULL);if (!virtual_dir)return -ENOMEM;return subsys_register(subsys, groups, virtual_dir);
}
中间会调用virtual_device_parent函数
struct kobject *virtual_device_parent(struct device *dev)
{static struct kobject *virtual_dir = NULL;if (!virtual_dir)virtual_dir = kobject_create_and_add("virtual",&devices_kset->kobj);return virtual_dir;
}
也就是在/sys/devices/下创建一个名字为“virtual”的目录。
Linux设备驱动模型-Bus相关推荐
- Linux设备驱动模型1——简介和底层架构
以下内容源于朱有鹏<物联网大讲堂>课程的学习整理,如有侵权,请告知删除. 一.linux设备驱动模型简介 1.什么是设备驱动模型? (1)类class.总线bus.设备device.驱动d ...
- linux设备驱动模型及其他,Linux设备驱动模型
Linux设备驱动模型,主要函数分析 整个驱动模型中,最核心的三个函数分别是 __bus_register.driver_register.device_register int __bus_regi ...
- linux平台设备驱动模型是什么意思,Linux设备驱动模型之我理解
点击(此处)折叠或打开 /* my_bus.c */ #include #include #include #include #include #include "my_bus.h&qu ...
- Linux设备驱动模型之platform(平台)总线详解
/********************************************************/ 内核版本:2.6.35.7 运行平台:三星s5pv210 /*********** ...
- Linux中kobject的作用,Linux设备驱动模型-- 数据结构Kset/KObject
前言 Kset和kobject是Linux设备驱动模型中的核心数据结构,其主要作用是将系统中的设备抽象出来,以树状结构组织,方便系统统一管理. 而这个统一管理的地方,就是sysfs,先放一张示例图,阐 ...
- Linux设备驱动模型三 kset
Linux设备驱动模型三 kset 1 kset数据结构 kset的定义在前文已有描述,我们再回顾一下: [cpp] view plain copy struct kset { /*与子kobject ...
- Linux设备驱动模型一 sysfs
Linux设备驱动模型一 sysfs 1 Linux设备模型 Linux 2.5的内核引入了一种新的设备模型,目的是对计算机上的所有设备进行统一的管理. 它包含以下基础结构: 类型 说明 设备Devi ...
- 五.linux设备驱动模型
站在设备驱动这个角度分析,设备驱动模型是如何构建出来,起到什么作用,认识它并在写驱动的时候去利用设备驱动模型 目录 一.linux 设备驱动模型简介 1.1. 什么是设备驱动模型 1.2. 为什么需要 ...
- 整理--linux设备驱动模型
知识整理–linux设备驱动模型 以kobject为底层,组织类class.总线bus.设备device.驱动driver等高级数据结构,同时实现对象引用计数.维护对象链表.对象上锁.对用户空间的表示 ...
- linux 内核驱动模型,linux设备驱动模型架构分析 一
linux设备驱动模型架构分析 一 发布时间:2018-07-04 15:14, 浏览次数:584 , 标签: linux 概述 LDD3中说:"Linux内核需要一个对系统结构的一般性描述 ...
最新文章
- [Matlab]二维统计分析图实例
- 向深度学习三剑客学习四种科研精神(上)
- 结合项目实例 回顾传统设计模式(二)观察者模式
- SupeSite后台添加新闻增加【预览】功能
- [转]VMware虚拟机上网络连接(network type)的三种模式--bridged、host-only、NAT
- 关于extjs中动态添加TabPanel的tab项并以iframe显示的整理(转)
- 智能机浏览器版本信息获取
- .NET 6 新特性 System.Text.Json 中的 Writeable DOM
- 产品经理是否应该给 UI 设计师的设计稿提意见?
- thinkphp5.0架构总览
- Facebook 洗白?欲打造以隐私为中心的社交平台!
- 力扣-811 子域名访问计数
- WAP网站源代码--WAP新闻(文章)系统调试实战
- 概率统计D 07.03 正态总体均值与方差的置信区间
- 《庄子·胠箧》:“彼窃钩者诛,窃国者为诸侯;诸侯之门而仁义存焉。”
- mysql 计算农历_SQL农历转换函数
- go get xxx timeout
- linux安装程序企鹅,Linux-小企鹅输入法的安装与使用
- document的用法
- 【学习分享】0、创龙 TMS320C6748开发例程使用手册
热门文章
- iOS支付宝支付总结
- ICSharpCode.SharpZipLib实现压缩解压缩
- Android性能优化方法(五)
- MFC-CFileException类学习笔记
- KVO.非常简单的键值监听模式
- python数据包pandas_python | 数据分析(二)- Pandas数据包
- python按键按下改变数值_「正点原子NANO STM32开发板资料连载」第十六章电容触摸按键实验...
- jquery中attr() 和 prop()的区别
- 将博客同步至CSDN
- 文本处理三剑客,正则表达式等