Linux驱动之设备模型(4)-总线
来源:互联网 发布:防木马软件 编辑:程序博客网 时间:2024/06/05 09:01
1 总线
总线,是处理器与一个或者多个设备之间的通道。在Linux设备模型中,所有的设备都通过总线相连,甚至是那些内部的虚拟"platform"总线。用bus_type结构来描述。
- struct bus_type {
- const char *name; /* 总线名 */
- const char *dev_name;
- struct device *dev_root;
- 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 iommu_ops *iommu_ops;
- /* 私有数据指针,这个比较重要的一个成员 */
- struct subsys_private *p;
- };
2. 总线声明
内核中的每一种总线类型(PCI,I2C,USB,etc)都用bus_type结构体来描述,需要初始化相应的name成员和match函数。
- struct bus_type pci_bus_type = {
- .name = "pci",
- .match = pci_bus_match,
- };
3. 注册和注销函数
int bus_register(struct bus_type *bus);
void bus_unregister(struct bus_type *bus);
总线 注册函数分析
- int bus_register(struct bus_type *bus)
- {
- retval =kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
- priv->subsys.kobj.kset = bus_kset;
- priv->subsys.kobj.ktype =&bus_ktype;
- priv->drivers_autoprobe = 1;
- /* 注册bus kset,在bus/下产生bus->name目录 */
- retval = kset_register(&priv->subsys);
- retval = bus_create_file(bus,&bus_attr_uevent);
- /* 产生device目录 */
- priv->devices_kset =kset_create_and_add("devices", NULL,
- &priv->subsys.kobj);
- /* 产生driver目录 */
- priv->drivers_kset =kset_create_and_add("drivers", NULL,
- &priv->subsys.kobj);
- /* 初始化设备链和驱动链 */
- klist_init(&priv->klist_devices,klist_devices_get, klist_devices_put);
- klist_init(&priv->klist_drivers,NULL, NULL);
- retval = add_probe_files(bus);
- retval = bus_add_attrs(bus);
- }
Klist_drivers和klist_devices这两条链非常重要,用来遍历drivers_kset和devices_kset,drivers_kset和devices_kset分别是总线上所有driver和device的集合。
4. match() 函数
match函数为总线提供了检测驱动是否支持此设备的功能,通过device IDs来进行匹配。当驱动被注册到总线上,总线上的设备链表会被遍历,match()被调用来完成对每个设备的匹配。
5. subsys_private
subsys_private是一个比较重要的成员。
- 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; /* 指回bus_type */
- struct kset glue_dirs;
- struct class *class;
- ;
设备链表和驱动链表连接了注册到总线上的所有设备和驱动,经常用来遍历和查询总线上的设备和驱动。设备模型核心层提供了两个API,用来遍历设备和驱动。
- int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data,
- int (*fn)(struct device *, void *));
- int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
- void * data, int (*fn)(struct device_driver *, void *));
6. 导出属性,总线的属性用bus_attribute来描述
- struct bus_attribute {
- struct attribute attr; /* 属性 */
- ssize_t (*show)(struct bus_type *, char * buf); /* 读属性方法 */
- ssize_t (*store)(struct bus_type *, const char * buf, size_t count); /* 写属性方法 */
- };
BUS_ATTR宏可以在编译时刻创建和初始化bus_attribute结构体
- BUS_ATTR(_name, _mode, _show, _store)
在LDM里提供了两个接口用来在sysfs目录下产生和移除属性文件
- int bus_create_file(struct bus_type *, struct bus_attribute *);
- void bus_remove_file(struct bus_type *, struct bus_attribute *);
7. 实例分析
创建一条scbus总线,并添加版本属性。实际中我们并不需要自己创建总线,此试验仅用来学习
- /*
- * for learn bus
- */
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/device.h>
- static char *Version = "revision 1.0,scbus";
- /* 匹配函数,通过设备名和驱动名来匹配 */
- static int scbus_match(struct device *dev,struct device_driver *driver)
- {
- printk("\n%s,%s\n", dev_name(dev), driver->name);
- return!strncmp(dev_name(dev), driver->name, strlen(driver->name));
- }
- static void scbus_release(struct device*dev)
- {
- printk("scbusrelease\n");
- }
- struct bus_type scbus_type = {
- .name = "scbus",
- .match = scbus_match,
- };
- EXPORT_SYMBOL_GPL(scbus_type);
- struct device scbus = {
- .init_name = "scbus0",
- .release = scbus_release,
- };
- EXPORT_SYMBOL_GPL(scbus);
- /*
- * export bus attribute
- */
- static ssize_t show_bus_version(structbus_type *bus, char *buf)
- {
- returnsnprintf(buf, PAGE_SIZE, "%s\n", Version);
- }
- static BUS_ATTR(version, S_IRUGO,show_bus_version, NULL);
- static int __init scbus_init(void)
- {
- intret;
- ret= bus_register(&scbus_type);
- if(ret)
- returnret;
- ret= bus_create_file(&scbus_type, &bus_attr_version);
- if(ret)
- gotocreate_error;
- ret= device_register(&scbus);
- if(ret)
- gotodevice_error;
- printk("Createa scbus\n");
- return0;
- device_error:
- bus_remove_file(&scbus_type,&bus_attr_version);
- create_error:
- bus_unregister(&scbus_type);
- returnret;
- }
- static void __exit scbus_exit(void)
- {
- device_unregister(&scbus);
- bus_remove_file(&scbus_type,&bus_attr_version);
- bus_unregister(&scbus_type);
- printk("Removea scbus\n");
- }
- module_init(scbus_init);
- module_exit(scbus_exit);
- MODULE_LICENSE("Dual BSD/GPL");
- MODULE_AUTHOR("CJOK<cjok.liao@gmail.com>");
试验结果:
- Linux驱动之设备模型(4)-总线
- Linux驱动之设备模型(4)-总线
- linux设备总线驱动模型 之 platform总线驱动
- linux设备总线驱动模型 之 platform总线驱动
- linux设备总线驱动模型 之 platform总线驱动
- Linux设备驱动模型之platform总线
- Linux设备驱动模型之platform总线
- Linux设备驱动模型之总线
- Linux设备驱动模型之platform总线
- Linux设备驱动之七----总线设备驱动模型
- linux设备模型之总线,设备,驱动模型
- 4、linux总线设备驱动模型
- Linux 设备总线驱动模型
- Linux总线设备驱动模型
- Linux总线、设备、驱动模型
- Linux总线设备驱动模型
- Linux 设备总线驱动模型
- Linux总线设备驱动模型
- android捕获ListView中每个item点击事件
- Android获取asset下的资源图片
- 第一次编程作业:计算两个数的最大公约数和《算法概论》的思维导图
- 鸟哥的Linux私房菜 基础学习篇读书笔记(1):Linux是什么
- Linux打包与压缩
- Linux驱动之设备模型(4)-总线
- Oracle死锁问题分析解决
- WARN No appenders could be found for logger的解决方法
- Spring-AOP-Struts重新解析
- Codeforces 401B Sereja and Contests(水题)
- 将UIView转成UIImage,将UIImage转成PNG/JPG
- 三 Gazebo学习总结之制作一个模型及导入网格
- 关于leveldb
- python socket文件通信练习