Linux驱动之设备模型(4)
2011-12-04 22:33
316 查看
5.总线
5.1 overview
前面我们介绍了设备模型的底层部分,下面我们来看下设备模型的高层部分,总线、设备和驱动
5.2 总线
l 总线,是处理器与一个或者多个设备之间的通道。在Linux设备模型中,用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);
struct subsys_private *p; /* 私有数据 */
};
Match函数 注册驱动或设备时被用来完成匹配
Uevent函数 用于热插拔,添加环境变量
Probe函数 匹配成功时调用,完成相应工作
P 私有数据,包含内嵌的kset,设备kset和链表,驱动kset和链表等
5.3 总线属性
l 总线属性用bus_attribute结构来表示
structbus_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);
};
BUS_ATTR(_name,_mode, _show, _store)
l 属性操作
n 创建属性
int bus_create_file(structbus_type *, struct bus_attribute *);
n 删除属性
voidbus_remove_file(struct bus_type *, struct bus_attribute *);
5.4 总线基本操作
l 总线注册和注销函数
n int bus_register(struct bus_type *bus);
n void bus_unregister(struct bus_type *bus);
l 遍历总线
n 遍历总线上每个驱动,并执行fn函数
intbus_for_each_drv(struct bus_type *bus, struct device_driver *start,
void *data, int (*fn)(struct device_driver*, void *));
n 遍历总线上每个设备,并执行fn函数
intbus_for_each_dev(struct bus_type *bus, struct device *start, void *data,
int (*fn)(struct device *dev, void *data));
l 总线注册分析
intbus_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的集合。
5.5 实例分析
创建一条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>");
试验结果:
转载自:http://blog.csdn.net/cjok376240497/article/details/7036444
5.1 overview
前面我们介绍了设备模型的底层部分,下面我们来看下设备模型的高层部分,总线、设备和驱动
5.2 总线
l 总线,是处理器与一个或者多个设备之间的通道。在Linux设备模型中,用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);
struct subsys_private *p; /* 私有数据 */
};
Match函数 注册驱动或设备时被用来完成匹配
Uevent函数 用于热插拔,添加环境变量
Probe函数 匹配成功时调用,完成相应工作
P 私有数据,包含内嵌的kset,设备kset和链表,驱动kset和链表等
5.3 总线属性
l 总线属性用bus_attribute结构来表示
structbus_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);
};
BUS_ATTR(_name,_mode, _show, _store)
l 属性操作
n 创建属性
int bus_create_file(structbus_type *, struct bus_attribute *);
n 删除属性
voidbus_remove_file(struct bus_type *, struct bus_attribute *);
5.4 总线基本操作
l 总线注册和注销函数
n int bus_register(struct bus_type *bus);
n void bus_unregister(struct bus_type *bus);
l 遍历总线
n 遍历总线上每个驱动,并执行fn函数
intbus_for_each_drv(struct bus_type *bus, struct device_driver *start,
void *data, int (*fn)(struct device_driver*, void *));
n 遍历总线上每个设备,并执行fn函数
intbus_for_each_dev(struct bus_type *bus, struct device *start, void *data,
int (*fn)(struct device *dev, void *data));
l 总线注册分析
intbus_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的集合。
5.5 实例分析
创建一条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>");
试验结果:
转载自:http://blog.csdn.net/cjok376240497/article/details/7036444
相关文章推荐
- Linux 设备驱动中的 I/O模型(二)—— 异步通知和异步I/O
- 67 linux内核里的framebuffer设备驱动模型
- Linux内核部件分析--设备驱动模型之device
- linux2.6标准字符设备驱动模型(手动注册)
- Linux驱动设备驱动模型
- Linux设备模型--驱动
- 2.1 Linux驱动设备模型
- 【转】Linux内核大讲堂 (一) 设备驱动的基石驱动模型(3)
- linux内核部件分析(五)——设备驱动模型的基石kobject
- Linux内核大讲堂 (一) 设备驱动的基石驱动模型(2)
- LINUX设备驱动之设备模型五--device&driver&bus(三)
- Linux设备模型之tty驱动架构分析
- 设备驱动-----Linux设备模型之input子系统详解
- 让天堂的归天堂,让尘土的归尘土——谈Linux的总线、设备、驱动模型
- Linux 设备驱动模型,I2C驱动,sys文件系统(1)
- linux设备模型之uart驱动架构分析
- Linux驱动程序开发 - 设备驱动模型初探
- Linux驱动之设备模型(4)
- Linux网络设备驱动(一) _驱动模型
- [Linux] 内核中 SPI 设备驱动模型(Platform设备驱动方式)