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

linux设备模型bus,device,driver

2012-08-02 17:58 387 查看

linux设备模型bus,device,driver

  虽然看了上面一篇转载的《使用/sys/访问系统》对总线,驱动,设备都讲得比较细但还是没有太多的感觉。在此就先把自己今天所学回忆一下。

  为了满足新的要求,linux2.6提供了新的设备模型:总线、驱动、设备。基本关系简要的概括如下:

驱动核心可以注册多种类型的总线。

每种总线下面可以挂载许多设备。(通过kset devices)

每种总线下可以用很多设备驱动。(通过包含一个kset drivers)}

每个驱动可以处理一组设备。按照我的理解就是所有的设备都挂载到总线上,当加载驱动时,驱动就支总线上找到自己对应的设备。或者先把驱动加载上,来了一个设备就去总线找驱动。

一:总线

  总线是处理器与设备之间通道,在设备模型中,所有的设备都通过总线相连

(1)bus_type.

struct bus_type {

const char * name;//设备名称


struct subsystem subsys;//代表自身

struct kset drivers; //当前总线的设备驱动集合

struct kset devices; //所有设备集合

struct klist klist_devices;

struct klist klist_drivers;

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, char **envp,

int num_envp, char *buffer, int buffer_size);//热拔插事件

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);

};

在后面的实例当中用到了里面的两个成员
1:const char *name;
2:[b] int (*match)(struct device * dev, struct device_driver * drv);//设备驱动匹配函数[/b]
这个匹配函数是很关键的东西,这是建立总线上设备与驱动的桥梁,当一个新的设备或驱动被添加到一个总线上时被调用。
(2)总线的操作:
注册:int bus_register(struct bus_type * bus)
注销:void bus_unregister(struct bus_type *bus);
(3)总线属性 bus_attribute
struct bus_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);

这个宏声明一个结构, 产生它的名子通过前缀字符串 bus_attr_ 到给定的名子.

任何属于一个总线的属性应当明确使用 bus_create_file 来创建:

int bus_create_file(struct bus_type *bus, struct bus_attribute *attr);

属性也可被去除, 使用:

void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr);

lddbus 驱动创建一个简单属性文件, 再次, 包含源码版本号. show 方法和 bus_attribute 结构设置如下:

static ssize_t show_bus_version(struct bus_type *bus, char *buf)

{

return snprintf(buf, PAGE_SIZE, "%s\n", Version);

}

这个总线属性现目前为止我还没有发现它的作用。

(4)总线实例:
其实在这个程序中操作很简单:
1:首先是要准备一个总线bus_type.也就是定义一个bus_type,然后给它填上一些成员。
定义如下:
struct bus_type my_bus_type = {

.name = "my_bus",

.match = my_match,

};

这里就对其两个成员赋值了。一个是名称。另一个则是匹配函数:
static int my_match(struct device *dev, struct device_driver *driver)

{

return !strncmp(dev->bus_id, driver->name, strlen(driver->name));

}

这是匹配的逻辑则是设备的名字与驱动的名字一样。
准备好了总线后就在模块初始化函数中注册:
/*注册总线*/

ret = bus_register(&my_bus_type);

if (ret)

return ret;

然后在模块退出函数中注解总线:
总线操作完后还要为总线创建属性文件:
static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);这句话就定义了一个总线属性文件。BUS_ATTR宏的定义如下:
bus_unregister(&my_bus_type);
#define BUS_ATTR(_name, _mode, _show, _store) \

struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)

show_bus_version定义如下:
static ssize_t show_bus_version(struct bus_type *bus, char *buf)

{

return snprintf(buf, PAGE_SIZE, "%s\n", Version);

}

定义好之后就是调用 函数创建文件
/*创建属性文件*/

if (bus_create_file(&my_bus_type, &bus_attr_version))

printk(KERN_NOTICE "Fail to create version attribute!\n");

总线本身也是要对应一个设备的。还要为总线创建设备。
static void my_bus_release(struct device *dev)

{

printk(KERN_DEBUG "my bus release\n");

}

struct device my_bus = {

.bus_id = "my_bus0",

.release = my_bus_release

};

/*注册总线设备*/

ret = device_register(&my_bus);

if (ret)

printk(KERN_NOTICE "Fail to register device:my_bus!\n");

可是这是有疑问,我还没有找到这个总线设备,和刚才的总线的联系。
源代码:
#include <linux/device.h>

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/init.h>

#include <linux/string.h>

MODULE_AUTHOR("David Xie");

MODULE_LICENSE("Dual BSD/GPL");

static char *Version = "$Revision: 1.9 $";

static int my_match(struct device *dev, struct device_driver *driver)

{

return !strncmp(dev->bus_id, driver->name, strlen(driver->name));

}

static void my_bus_release(struct device *dev)

{

printk(KERN_DEBUG "my bus release\n");

}

struct device my_bus = {

.bus_id = "my_bus0",

.release = my_bus_release

};

struct bus_type my_bus_type = {

.name = "my_bus",

.match = my_match,

};

EXPORT_SYMBOL(my_bus);

EXPORT_SYMBOL(my_bus_type);

/*

* Export a simple attribute.

*/

static ssize_t show_bus_version(struct bus_type *bus, char *buf)

{

return snprintf(buf, PAGE_SIZE, "%s\n", Version);

}

static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);

static int __init my_bus_init(void)

{

int ret;

/*注册总线*/

ret = bus_register(&my_bus_type);

if (ret)

return ret;

/*创建属性文件*/

if (bus_create_file(&my_bus_type, &bus_attr_version))

printk(KERN_NOTICE "Fail to create version attribute!\n");

/*注册总线设备*/

ret = device_register(&my_bus);

if (ret)

printk(KERN_NOTICE "Fail to register device:my_bus!\n");

return ret;

}

static void my_bus_exit(void)

{

device_unregister(&my_bus);

bus_unregister(&my_bus_type);

}

module_init(my_bus_init);

module_exit(my_bus_exit);

二:设备:

1:
struct device {
struct device * parent; //父设备,一般一个bus也对应一个设备。

struct kobject kobj;//代表自身

char bus_id[BUS_ID_SIZE];

struct bus_type * bus; /* 所属的总线 */

struct device_driver *driver; /* 匹配的驱动*/

void *driver_data; /* data private to the driver 指向驱动 */

void *platform_data; /* Platform specific data,由驱动定义并使用*/

///更多字段忽略了
};
注册设备:int device_register(sruct device *dev)
注销设备:void device_unregister(struct device *dev);
2:设备属性:
sysfs 中的设备入口可有属性. 相关的结构是:

struct device_attribute {

struct attribute attr;

ssize_t (*show)(struct device *dev, char *buf);

ssize_t (*store)(struct device *dev, const char *buf,

size_t count);

};

这些属性结构可在编译时建立, 使用这些宏:

DEVICE_ATTR(name, mode, show, store);

结果结构通过前缀 dev_attr_ 到给定名子上来命名. 属性文件的实际管理使用通常的函数对来处理:

int device_create_file(struct device *device, struct device_attribute *entry);

void device_remove_file(struct device *dev, struct device_attribute *attr);

struct bus_type 的 dev_attrs 成员指向一个缺省的属性列表, 这些属性给添加到总线的每个设备创建.

3:创建设备实例:
创建设备和创建总线基本一样这里只贴出程序:
#include <linux/device.h>

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/init.h>

#include <linux/string.h>

MODULE_AUTHOR("David Xie");

MODULE_LICENSE("Dual BSD/GPL");

extern struct device my_bus;

extern struct bus_type my_bus_type;

/* Why need this ?*/

static void my_dev_release(struct device *dev)

{

}

struct device my_dev = {

.bus = &my_bus_type,//与总线接上关系

.parent = &my_bus,//与总线设备接上关系

.release = my_dev_release,

};

/*

* Export a simple attribute.

*/

static ssize_t mydev_show(struct device *dev,struct device_attribute *attr, char *buf)

{

return sprintf(buf, "%s\n", "This is my device!");

}

static DEVICE_ATTR(dev, S_IRUGO, mydev_show, NULL);

static int __init my_device_init(void)

{

int ret = 0;

/* 初始化设备 */

strncpy(my_dev.bus_id, "my_dev", BUS_ID_SIZE);

/*注册设备*/

device_register(&my_dev);

/*创建属性文件*/

device_create_file(&my_dev, &dev_attr_dev);

return ret;

}

static void my_device_exit(void)

{

device_unregister(&my_dev);

}

module_init(my_device_init);

module_exit(my_device_exit);

三:设备驱动:

在总线上挂载了设备后就要为其准备驱动程序。

驱动程序的实现与设备的实现类似,代码如下:

#include <linux/device.h>

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/init.h>

#include <linux/string.h>

MODULE_AUTHOR("David Xie");

MODULE_LICENSE("Dual BSD/GPL");

extern struct bus_type my_bus_type;

static int my_probe(struct device *dev)

{

printk("Driver found device which my driver can handle!\n");

return 0;

}

static int my_remove(struct device *dev)

{

printk("Driver found device unpluged!\n");

return 0;

}

struct device_driver my_driver = {

.name = "my_dev",//对应的设备名称

.bus = &my_bus_type,//挂载的总线

.probe = my_probe,//这个函数就是在找到与自己对应的设备时被调用。

.remove = my_remove,

};

/*

* Export a simple attribute.

*/

static ssize_t mydriver_show(struct device_driver *driver, char *buf)

{

return sprintf(buf, "%s\n", "This is my driver!");

}

static DRIVER_ATTR(drv, S_IRUGO, mydriver_show, NULL);

static int __init my_driver_init(void)

{

int ret = 0;

/*注册驱动*/

driver_register(&my_driver);

/*创建属性文件*/

driver_create_file(&my_driver, &driver_attr_drv);

return ret;

}

static void my_driver_exit(void)

{

driver_unregister(&my_driver);

}

module_init(my_driver_init);

module_exit(my_driver_exit);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: