您的位置:首页 > 运维架构 > Linux

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: